I'm practicing with concurrency in C, and I seem to encounter some problems with semaphores. I'm using Xcode 6.3.2 in MacOSX.
Here it is a sample program that seems to act strangely: the purpose of the example is to print either ABCD or BACD strings
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
void *thread1(void*);
void *thread2(void*);
sem_t *sem0, *sem1, *sem2;;
int main(int argc, const char * argv[]) {
pthread_t t1, t2;
sem0 = sem_open("sem0", O_CREAT, 0600, 2);
sem1 = sem_open("sem1", O_CREAT, 0600, 0);
sem2 = sem_open("sem2", O_CREAT, 0600, 0);
// quick check
if (sem0 == SEM_FAILED || sem1 == SEM_FAILED || sem2 == SEM_FAILED) {
printf("Something went wrong\n");
return 0;
}
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
sem_close(sem0);
sem_close(sem1);
sem_close(sem2);
return 0;
}
void *thread1(void* arg) {
int n=0;
while (n<10) {
sem_wait(sem0);
printf("A");
fflush(stdout);
sem_wait(sem1);
printf("C");
fflush(stdout);
sem_post(sem2);
n++;
}
pthread_exit(NULL);
}
void *thread2(void* arg) {
int n=0;
while (n<10) {
sem_wait(sem0);
printf("B");
fflush(stdout);
sem_post(sem1);
sem_wait(sem2);
printf("D\n");
fflush(stdout);
sem_post(sem0);
sem_post(sem0);
n++;
}
pthread_exit(NULL);
}
If I implemented correctly the semaphores, the result would be either ABCD or BACD, but in reality I get a whole variety of strange output.
I will include part of that output here
ABCD
BAD
CABCD
BAD
CBAD
CBAD
CBAD
CBAD
CBAD
CBAD
C
Is someone able to help me? Thanks in advance
IMPORTANT EDIT: I downloaded Ubuntu, and the code is working smoothly there, no problems at all. So, to resume
- MacOSX 10.10.3 with Xcode 6.3.2 --> Not working properly
- Ubuntu 15.04 --> Working properly
Don't know why.
Printf is accessing one resource, the standard out file descriptor. You need to request a lock to allow access to stdout by only one thread at a time. Otherwise you may get interleaved text. I'm not sure why you're creating three semaphores, but consider that if you have multiple semaphores blocking the same resource, you have multiple windows open to that resource. If you only close one at a time, then you're not really blocking the resource at all.
edit: An example. thread 1 locks sem 0, thread 2 waits. thread 1 unlocks sem0 and thread 2 can continue. Thread 1 now locks sem1. They're both writing to standard out though. That means that they both, even obeying your locks, are allowed write to stdout.
Why it doesn't happen earlier is just due to thread contention.
edit 2: I think John's right in that my original explanation doesn't cover your question. I can't reproduce your output, and I can't imagine a path to your output. Even with the fflush example someone else mentioned, I still don't see how that particular string would be formed even using the same buffer with the way your semaphores should be working. I can only guess to this: