Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C, pthreads, semaphore.h - Problem

1 view
Skip to first unread message

Ken Very Big Liar

unread,
May 1, 2002, 3:56:47 PM5/1/02
to
(Note for comp.programming.threads; this program was compiled and run under the
AS/400. I also realize that this program uses 1 or 2 non-standard pthread
routines. I am working on a Linux port now).

I would expect this program to at one time print the message "Semaphore is
locked", but it doesn't. All three threads are created at the same time and
they all try to use the same resource (sleep()), and they all get use of the
semaphore and immediately go into the sleep() system call. Any knowledgable
person show me the error of my ways?

A separate question: is there a way to run multithreaded apps using the CALL
statement? I have to use SBMJOB CMD(CALL PGM(semaphore )) ALWMLTTHD(*YES) to
get this to run.

Thanks!

Output:
-----
THREAD 347: sem_open() worked
THREAD 348: sem_open() worked
THREAD 349: sem_open() worked
THREAD 347: sem_trywait() worked
THREAD 347: sleeping...
THREAD 348: sem_trywait() worked
THREAD 348: sleeping...
THREAD 349: sem_trywait() worked
THREAD 349: sleeping...
THREAD 348: sem_post() worked
THREAD 347: sem_post() worked
THREAD 349: sem_post() worked
-----

Code:
-----
#define _MULTI_THREADED /* You MUST define this before including pthread.h
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>

#define Number_Of_Tasks 3


void *Task(void *parm)
{
int rc, pid;
sem_t *semaphore = NULL;


pid = pthread_getthreadid_np().intId.lo;

/*
Create a named semaphore.
*/
if ((semaphore = sem_open("/semaphore1", O_CREAT, 0666, 5)) == SEM_FAILED) {
perror("sem_open()");
exit(0);
}
printf("THREAD %d: sem_open() worked\n", pid);

/*
sem_trywait() looks to see if the semaphore is available for locking. If it isn't, then it exits w/ and error and sets
errno to EAGAIN.
*/
while ((rc = sem_trywait(semaphore)) == -1 && errno == EAGAIN) {
printf("THREAD %d: Semaphore is locked\n", pid);
}
printf("THREAD %d: sem_trywait() worked\n", pid);
printf("THREAD %d: sleeping...\n", pid);

/*
Even though we have passed the sem_trywait(), make sure we don't have another errno situation.
*/
if (rc == -1) {
perror("sem_trywait()");
exit(0);
}

/*
At this point we should have our semaphore, so do some work on our resource...

... blah blah blah
*/
sleep(20);

/*
Now release our lock on the semaphore. You should never see this function fail.
*/
if (sem_post(semaphore)) {
perror("sem_post()");
}
printf("THREAD %d: sem_post() worked\n", pid);

/*
Now close our semaphore. We could also remove it by calling sem_unlink(sema);.
*/
sem_close(semaphore);

return __VOID(0);
}


int main(int argc, char *argv[])
{
int rc, i;
pthread_t tasks[Number_Of_Tasks];
void *status;

for (i = 0; i < Number_Of_Tasks; ++i) {
if (rc = pthread_create(&tasks[i], NULL, Task, (void *)0)) {
printf("LINE %d: pthread_create(): Fatal error line %s\n", __LINE__, strerror(rc));
exit(1);
}
}

for (i = 0; i < Number_Of_Tasks; ++i) {
if (rc = pthread_join(tasks[i], &status)) {
printf("LINE %d: pthread_ join() failed for server thread. Error is %s", __LINE__, strerror(rc));
}
}
}

---

Kelly Beard

"I got sunshine in my stomach
Like I just rocked my baby to sleep.
I got sunshine in my stomach
But I can't keep me from creeping sleep,
Sleep, deep in the deep." -- Genesis "In The Cage"

Steve Watt

unread,
May 1, 2002, 6:11:01 PM5/1/02
to
In article <etg0du09os8ja06s5...@4ax.com>,

Ken Very Big Liar <kellyde...@hotmail.com> wrote:
>I would expect this program to at one time print the message "Semaphore is
>locked", but it doesn't.

That's because you're initializing the semaphore (which is a counting entity)
with a value of 5. Therefore you can call sem_wait() 5 times before one
needs to block.

>A separate question: is there a way to run multithreaded apps using the CALL
>statement? I have to use SBMJOB CMD(CALL PGM(semaphore )) ALWMLTTHD(*YES) to
>get this to run.

Ouch. It's been so long since I've looked at jcl and children...

[ ... ]

> /*
> Create a named semaphore.
> */
> if ((semaphore = sem_open("/semaphore1", O_CREAT, 0666, 5)) == SEM_FAILED) {

That unadorned "5" is the number of times the semaphore may be waited on before
a wait will block. Since you only create 3 threads, you'll never see your
blocking message.
--
Steve Watt KD6GGD PP-ASEL-IA ICBM: 121W 56' 57.8" / 37N 20' 14.9"
Internet: steve @ Watt.COM Whois: SW32
Free time? There's no such thing. It just comes in varying prices...

Ken Very Big Liar

unread,
May 2, 2002, 9:45:57 AM5/2/02
to
On Wed, 1 May 2002 22:11:01 GMT, st...@nospam.Watt.COM (Steve Watt) wrote:

>
>That unadorned "5" is the number of times the semaphore may be waited on before
>a wait will block. Since you only create 3 threads, you'll never see your
>blocking message.

Help me understand. Why would you want to initialize a semaphore to anything
more than 1? Manual pages are notoriously bad at not explaining what an API is
used for.

Alexander Terekhov

unread,
May 2, 2002, 10:53:17 AM5/2/02
to

Ken Very Big Liar wrote:
>
> On Wed, 1 May 2002 22:11:01 GMT, st...@nospam.Watt.COM (Steve Watt) wrote:
>
> >
> >That unadorned "5" is the number of times the semaphore may be waited on before
> >a wait will block. Since you only create 3 threads, you'll never see your
> >blocking message.
>
> Help me understand. Why would you want to initialize a semaphore to anything
> more than 1? Manual pages are notoriously bad at not explaining what an API is
> used for.

http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
(please pay attention to "Much experience with semaphores shows...",
"With respect to binary semaphores, experience has shown..." and
".......It is for these reasons that IEEE Std 1003.1-2001 allows
semaphores to be used by threads. .... Mutexes and condition
variables together constitute an appropriate, sufficient, and
complete set of inter-thread synchronization primitives.")

Also:

http://groups.google.com/groups?selm=c29b5e33.0201310709.3ffc3476%40posting.google.com
(Subject: Re: mutex or semaphores?)

and, perhaps:

http://publib.boulder.ibm.com/html/as400/v5r1/ic2924/info/rzahw/rzahwmst.pdf
("iSeries/Programming Multithreaded applications")

regards,
alexander.

Ken Very Big Liar

unread,
May 2, 2002, 1:06:56 PM5/2/02
to
On Thu, 02 May 2002 16:53:17 +0200, Alexander Terekhov <tere...@web.de> wrote:

>
>http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
>(please pay attention to "Much experience with semaphores shows...",
> "With respect to binary semaphores, experience has shown..." and
> ".......It is for these reasons that IEEE Std 1003.1-2001 allows
> semaphores to be used by threads. .... Mutexes and condition
> variables together constitute an appropriate, sufficient, and
> complete set of inter-thread synchronization primitives.")
>
>Also:
>
>http://groups.google.com/groups?selm=c29b5e33.0201310709.3ffc3476%40posting.google.com
>(Subject: Re: mutex or semaphores?)
>
>and, perhaps:
>
>http://publib.boulder.ibm.com/html/as400/v5r1/ic2924/info/rzahw/rzahwmst.pdf
>("iSeries/Programming Multithreaded applications")
>
>regards,
>alexander.

Thanks for the links. I also found a Java related article on www.cuj.com that
helps. I finally worked out the kinks in my original program. Here is the
final result:

-----
#define _MULTI_THREADED /* You MUST define this before including pthread.h
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>

#define Number_Of_Tasks 3


void *Task(void *parm)
{
int rc, pid, first_time;
sem_t *semaphore = NULL;
pthread_t pt;


/*
Equivalent to get the process id for each thread. Helps to sort out where the messages are coming from.
*/
pid = pthread_self().reservedLoId;

/*
Open the already created named semaphore.
*/
if ((semaphore = sem_open("/semaphore1", 0)) == SEM_FAILED) {
perror("sem_open()");
return __VOID(0);


}
printf("THREAD %d: sem_open() worked\n", pid);

/*
sem_trywait() looks to see if the semaphore is available for locking. If it isn't, then it exits w/ an error and sets
errno to EAGAIN.
*/
first_time = 1;


while ((rc = sem_trywait(semaphore)) == -1 && errno == EAGAIN) {

if (first_time) {
first_time = 0;


printf("THREAD %d: Semaphore is locked\n", pid);
}
}
printf("THREAD %d: sem_trywait() worked\n", pid);
printf("THREAD %d: sleeping...\n", pid);

/*
Even though we have passed the sem_trywait(), make sure we don't have another errno situation.
*/
if (rc == -1) {

printf("THREAD %d: sem_trywait() %s\n", pid, strerror(errno));
return __VOID(0);
}

/*
At this point we should have our semaphore, so do some work on our resource...

... blah blah blah
*/
sleep(20);

/*
Now release our lock on the semaphore. You should never see this function fail.
*/
if (sem_post(semaphore)) {
perror("sem_post()");
}
printf("THREAD %d: sem_post() worked\n", pid);


/*
Even though you called sem_open() here, you do NOT call sem_close(). To do so would close the semaphore for everybody.
sem_open() will open the semaphore and if it is already open, just gives you a copy of the pointer the system is
maintaining.
*/
return __VOID(0);
}


int main(int argc, char *argv[])
{
int rc, i;
pthread_t tasks[Number_Of_Tasks];
void *status;

sem_t *semaphore = NULL;


/*
Open and create our semaphore. Each of the threads also calls sem_open() because they need a local semaphore variable,
but we could just have easily made the semaphore variable global for everyone to use.
*/
if ((semaphore = sem_open("/semaphore1", O_CREAT, 0666, 1)) == SEM_FAILED) {
perror("sem_open()");
exit(0);
}

/*
Create threads. These threads will try and allocate the semaphore in turn so that they can execute their critical section,
which is just a sleep().
*/


for (i = 0; i < Number_Of_Tasks; ++i) {
if (rc = pthread_create(&tasks[i], NULL, Task, (void *)0)) {
printf("LINE %d: pthread_create(): Fatal error line %s\n", __LINE__, strerror(rc));
exit(1);
}
}

for (i = 0; i < Number_Of_Tasks; ++i) {
if (rc = pthread_join(tasks[i], &status)) {
printf("LINE %d: pthread_ join() failed for server thread. Error is %s", __LINE__, strerror(rc));
}
}

printf("MAIN ENDING\n");

sem_close(semaphore);
sem_unlink("/semaphore1");

Joel S. Mueller

unread,
May 2, 2002, 1:22:57 PM5/2/02
to
No (can't create threads in an interactive job). Use the SPAWN command in
QUSRTOOL (or SBMJOB like you noted).

--
Joel S. Mueller

"Ken Very Big Liar" <kellyde...@hotmail.com> wrote in message
news:etg0du09os8ja06s5...@4ax.com...

Alexander Terekhov

unread,
May 2, 2002, 1:56:30 PM5/2/02
to

Ken Very Big Liar wrote:
[...]

> I also found a Java related article on www.cuj.com that helps.

Do you have a link?

regards,
alexander.

Daniel Miller

unread,
May 2, 2002, 2:32:42 PM5/2/02
to
Ken wrote:

> On Wed, 1 May 2002 22:11:01 GMT, st...@nospam.Watt.COM (Steve Watt) wrote:
>
>
>>That unadorned "5" is the number of times the semaphore may be waited on before
>>a wait will block. Since you only create 3 threads, you'll never see your
>>blocking message.
>>
>
> Help me understand. Why would you want to initialize a semaphore to anything
> more than 1? Manual pages are notoriously bad at not explaining what an API is
> used for.


Conceptually semaphores model the doling out of resources from a pool. The
concept of "resource" can be quite concrete or purely conceptual/academic from
application to application. Likewise, the concept of "pool" can be quite
concrete or purely conceptual/academic from application to application. But
none the less (despite any objections) it is conceptually insightful & revealing
& simplifying to consider semaphores as being a model of doling out resources
from a pool, especially when considering questions such as the original posting.
The value of the count of the semaphore is the number of unallocated resources
in that semaphore's corresponding pool.

There are two general categories of pools of resources:
semaphore#1) those pools which start out at size zero and grow to
great-than-zero size as resources are born/created (where those resources later
are later killed/consumed) VERSUS
semaphore#2) those pools which start out at greater-than-zero size (e.g.,
often a fixed maximum size, although variations on this theme exist) which are
consumed/allocated, ultimately to the point that the pool's resources are all
in-use leaving a zero number of unallocated resources in the pool and thus the
semaphore count at zero.

In semaphore#1 when no resources exist in the pool (i.e., semaphore's count
is zero), threads which intend to consume pend on the semaphore awaiting more
resources to be produced. In semaphore#2 when all resources in the pool are
allocated (i.e., semaphore's count is zero), threads which request
permission-to-access pend on the semaphore awaiting the deallocation of a resource.

By the way often applications falling into the category of semaphore#1 fit
into a category called "producer-consumer", such as seen in RTOS message-queues
where the queue starts out empty, has elements pushed into the message-queue in
FIFO order by one or more threads, and has elements popped from the
message-queue by one or more threads pending on that single message-queue.

(Note that birth/production in this producer-consumer model does not
necessarily mean malloc in C nor invocation of ctor in C++ at the moment of
birth/production. Likewise note that death/consumption in this
producer-consumer model does not necessarily mean free in C nor invocation of
dtor in C++ at the moment of death/consumption. These birth/death or
production/consumption concepts are referring to the entry of the resource to
the pool/container and the exit of the resource from the pool/container, not
necessarily to the resource itself if the resource has a lifetime larger than
the time-period/system-state where it existed as a member of the pool/container.)

Often one hears the terms "binary semaphore" and "counting (a.k.a., Dijkstra)
semaphore". I personally find the term "binary semaphore" irritating---that is
what the term "mutex" is for---, but let's put the term "binary semaphore" into
this dole-resources-from-pool context. Binary semaphores can be considered as
doling out permission to access a member of a pool composed of a single
resource. The pool of single resource has size one. The semaphore (and thus
pool-size) is initialized to one to indicate that permission to the element in
that pool has yet to be doled out. When the need to have permission to access
the doled-out resource has ceased, the resource is released back to its pool of
size one. Obviously, binary semaphores are the degenerate case of
counting/Dijkstra semaphore: counting between 1 and 0. Or equivalently, binary
semaphore's single-resource pool is a pool of degenerate size (1) where the
number of unallocated elements in the pool varies between 1 and 0.

Counting/Dijkstra semaphores are capable of doling out resources from
nondegenerately-sized pools, where pool size may be greater than one.

RTOS = real-time operating system
FIFO = first-in first-out

Ken Very Big Liar

unread,
May 2, 2002, 3:27:31 PM5/2/02
to
On Thu, 2 May 2002 12:22:57 -0500, "Joel S. Mueller"
<Joel_M...@TAKEOUT.us.ibm.com> wrote:

>No (can't create threads in an interactive job). Use the SPAWN command in
>QUSRTOOL (or SBMJOB like you noted).

I did find that you can run multithreaded jobs under the QSHELL environment.
You have to define QIBM_MULTI_THREADED=Y. Actually, I'm able to run
multithreaded jobs in my qsh without having to define this environment variable.

Ken Very Big Liar

unread,
May 2, 2002, 3:29:40 PM5/2/02
to
On Thu, 02 May 2002 19:56:30 +0200, Alexander Terekhov <tere...@web.de> wrote:

>
>Ken Very Big Liar wrote:
>[...]
>> I also found a Java related article on www.cuj.com that helps.
>
>Do you have a link?
>

Very interesting article. Helps explain an application of semaphores and
mutexes, but it's just an interesting project all around.

http://www.cuj.com/java/articles/a10.htm?topic=java&topic=java

Ken Very Big Liar

unread,
May 2, 2002, 3:44:17 PM5/2/02
to
Nicely done. Saved for the future. I was using my program as a 'binary'
semaphore example. It prevents multiple threads from accessing the same code or
other resource. So really a mutex is more appropriate here, but i was trying to
learn the semaphore APIs here. Thanks much.

On Thu, 02 May 2002 13:32:42 -0500, Daniel Miller <daniel...@tellabs.com>
wrote:

> Conceptually semaphores model the doling out of resources from a pool. The
>concept of "resource" can be quite concrete or purely conceptual/academic from
>application to application. Likewise, the concept of "pool" can be quite
>concrete or purely conceptual/academic from application to application. But
>none the less (despite any objections) it is conceptually insightful & revealing
> & simplifying to consider semaphores as being a model of doling out resources
>from a pool, especially when considering questions such as the original posting.
> The value of the count of the semaphore is the number of unallocated resources
>in that semaphore's corresponding pool.
>

---

Alexander Terekhov

unread,
May 3, 2002, 3:33:26 AM5/3/02
to

Ken Very Big Liar wrote:
[...]
>
> http://www.cuj.com/java/articles/a10.htm?topic=java&topic=java

Ha ha ha .... ha <almost ROFLWTIME>, *THANK YOU*! Folks, enjoy:

"....
Java also provides protection for shared resources
that are used within different threads within the
same program and are not encapsulated within a single
method.

This protection is accomplished via Java's version
of the mutex; in Java, every object implicitly
implements a mutex by inheriting the wait, notify,
and notifyAll methods of Object (the base class of
all Java objects).

To protect a critical piece of code via the Java
mutex, the programmer places a call to wait within
the source code, immediately before the code to be
protected; and a call to either notify or notifyAll
immediately after the critical section.

When a thread executes wait, one of two things
happens. If no other thread has executed wait,
wait does not block, and the thread passes through,
gaining access to the critical code. On the other
hand, if another thread has already execute wait,
processing on the current thread is suspended wait
blocks until another thread calls notify or notifyAll.
(If wait is called without arguments it blocks forever.
wait can also take timeout parameters, which include
the number of seconds and nanoseconds to wait before
timing out.)

When a thread has finished executing a critical
section of code, it calls either notify or
notifyAll to allow other threads to access the
critical section. The difference between notify
and notifyAll is that notify will inform just
one thread that it can stop waiting, whereas
notifyAll informs all waiting threads. The use
of notify is problematic if multiple threads
are running, because it notifies only one other
thread. The thread of choice is arbitrary and
the one chosen is not guaranteed to be waiting
at the time notify is called. This means that
the waiting threads remain blocked in their
wait state since they have not been notified.
To make sure all threads receive the notify
signal, you can use notifyAll. Then if multiple
threads are waiting, one is arbitrarily chosen
to discontinue waiting. The conclusion to be
drawn from this is to always use notifyAll to
avoid potential deadlock problems.
...."

http://www.cuj.com/java/articles/a10_fig.htm?topic=java#x2
("Listing 1: The Mutex class", etc.)

regards,
alexander.

P.S. http://gee.cs.oswego.edu/dl/concurrency-interest/aims.html
("JSR 166 Initial Aims and Scope....")

and, perhaps:


http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
("Overview of package util.concurrent Release 1.3.1. ....")

0 new messages