Pthreads + semaphores, why is this not executing correctly?

This is the assignment I'm working on. It should use semaphores, not a mutex.

#include <stdio.h> #include <pthread.h> #include <assert.h> #include <unistd.h> #include <semaphore.h> #include <fcntl.h> sem_t *ab, *ac, *ad, *de, *ce, *bf, *ef; void *a(void *arg) { printf("Entering A...\n"); sleep(1); printf("Exiting A...\n"); assert(sem_post(ab)==0); assert(sem_post(ac)==0); assert(sem_post(ad)==0); pthread_exit((void *)99); } void *b(void *arg) { assert(sem_wait(ab)==0); printf("Entering B...\n"); sleep(1); printf("Exiting B...\n"); assert(sem_post(bf)==0); pthread_exit((void *)99); } void *c(void *arg) { assert(sem_wait(ac)==0); printf("Entering C...\n"); sleep(1); printf("Exiting C...\n"); assert(sem_post(ce)==0); pthread_exit((void *)99); } void *d(void *arg) { assert(sem_wait(ad)==0); printf("Entering D...\n"); sleep(1); printf("Exiting D...\n"); assert(sem_post(de)==0); pthread_exit((void *)99); } void *e(void *arg) { assert(sem_wait(ce)==0); assert(sem_wait(de)==0); printf("Entering E...\n"); sleep(1); printf("Exiting E...\n"); assert(sem_post(ef)==0); pthread_exit((void *)99); } void *f(void *arg) { assert(sem_wait(bf)==0); assert(sem_wait(ef)==0); printf("Entering F...\n"); sleep(1); printf("Exiting F...\n"); pthread_exit((void *)99); } int main() { pthread_t _a, _b, _c, _d, _e, _f; int r1, r2, r3, r4, r5, r6; ab=sem_open("foobar", O_CREAT, 0700, 0); ac=sem_open("foobar", O_CREAT, 0700, 0); ad=sem_open("foobar", O_CREAT, 0700, 0); ce=sem_open("foobar", O_CREAT, 0700, 0); de=sem_open("foobar", O_CREAT, 0700, 0); ef=sem_open("foobar", O_CREAT, 0700, 0); bf=sem_open("foobar", O_CREAT, 0700, 0); /*sem_init(ab,0,1); sem_init(ac,0,1); sem_init(ad,0,1); sem_init(ce,0,1); sem_init(de,0,1); sem_init(ef,0,1); sem_init(bf,0,1);*/ assert(pthread_create(&_a, NULL, a, &r1) == 0); assert(pthread_create(&_b, NULL, b, &r2) == 0); assert(pthread_create(&_c, NULL, c, &r3) == 0); assert(pthread_create(&_d, NULL, d, &r4) == 0); assert(pthread_create(&_e, NULL, e, &r5) == 0); assert(pthread_create(&_f, NULL, f, &r6) == 0); assert(pthread_join(_a, NULL) == 0); assert(pthread_join(_b, NULL) == 0); assert(pthread_join(_c, NULL) == 0); assert(pthread_join(_d, NULL) == 0); assert(pthread_join(_e, NULL) == 0); assert(pthread_join(_f, NULL) == 0); assert( sem_close(ab)==0 ); assert( sem_close(ac)==0 ); assert( sem_close(ad)==0 ); assert( sem_close(ce)==0 ); assert( sem_close(de)==0 ); assert( sem_close(bf)==0 ); assert( sem_close(ef)==0 ); return 0; } 

This is pretty simple, but for some reason it is not running in the correct order. The conclusion is far from consistent, but always incorrect. Here is one example:

Entering A ...
Entering B ... <---- sem_post (ab) has not yet been called
Exit ... Enter C ...
Entering D ...
Exit ... Exit ... Exit ... Enter E ...
Entering F ...
Output F ...
Exit E ...

He should follow this diagram:

wCAXE.jpg

Any help with this would be greatly appreciated, but it’s an appointment, so don’t start telling me to do it in a completely different way and not give the answer directly, just point me in the right direction.

+4
source share
2 answers

In your code, A is not locked before printing the output line with ab .

This means that when he comes back from sleep, he can do whatever he wants, because he does not depend on blocking or anything else.

You must use semaphores to stop another thread / function. sleep () simply gives the processor the amount of time you specify, after which they can continue.

Note:

You probably don't need to use sleep. threads will refuse the CPU if they cannot block

0
source

You have two problems. First, you only have one semaphore called foobar , which you open seven times. The second problem is that the named semaphores are stable - they stay around (and keep the same value) until you call sem_unlink() on them. Since you never do this, it is likely that the foobar semaphore starts with a value greater than zero from the previous run of your program.

You can fix these problems using sem_unlink() to make sure semaphores do not exist before they are created, and using a different name for each semaphore.

Also, you really should use unnamed semaphores created with sem_init() instead of sem_open() . To do this, you will change your ab , ac , ... declarations to:

 sem_t ab, ac, ad, de, ce, bf, ef; 

Then you modify all calls to sem_post() and sem_wait() so that they use &ab , &ac , ...:

 void *a(void *arg) { printf("Entering A...\n"); sleep(1); printf("Exiting A...\n"); assert(sem_post(&ab)==0); assert(sem_post(&ac)==0); assert(sem_post(&ad)==0); pthread_exit((void *)99); } 

You would replace the calls to sem_open() with sem_init() :

 sem_init(&ab, 0, 0); sem_init(&ac, 0, 0); sem_init(&ad, 0, 0); sem_init(&ce, 0, 0); sem_init(&de, 0, 0); sem_init(&ef, 0, 0); sem_init(&bf, 0, 0); 

Finally, replace the sem_close() calls with sem_destroy() :

 assert( sem_destroy(&ab)==0 ); assert( sem_destroy(&ac)==0 ); assert( sem_destroy(&ad)==0 ); assert( sem_destroy(&ce)==0 ); assert( sem_destroy(&de)==0 ); assert( sem_destroy(&bf)==0 ); assert( sem_destroy(&ef)==0 ); 

When I make changes above your code, I get the following output, which I believe is what you expect:

 Entering A... Exiting A... Entering B... Entering C... Entering D... Exiting B... Exiting C... Exiting D... Entering E... Exiting E... Entering F... Exiting F... 
+2
source

All Articles