Reputation: 91
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
Don't know why.
Upvotes: 3
Views: 322
Reputation: 340168
There's a typo when you call sem_open()
for sem2
- the name passed in is "sem1"
:
sem1 = sem_open("sem1", O_CREAT, 0600, 0);
sem2 = sem_open("sem1", O_CREAT, 0600, 0);
// ^^^^
So the pointers sem1
and sem2
would be referring to the same semaphore.
Upvotes: 1
Reputation: 427
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:
Upvotes: 0
Reputation: 78903
Your problem is probably that printf
output is buffered and shared between threads. You'd have to ensure to empty the buffer with fflush
before posting on the semaphores.
Upvotes: 2