我在C中练习并发,我似乎遇到了一些信号量问题。 我在MacOSX中使用Xcode 6.3.2。
这是一个看似奇怪的示例程序:示例的目的是打印ABCD或BACD字符串
#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);
}
如果我正确实现了信号量,结果将是ABCD或BACD,但实际上我得到了各种奇怪的输出。
我将在此处包含部分输出
ABCD
BAD
CABCD
BAD
CBAD
CBAD
CBAD
CBAD
CBAD
CBAD
C
有人能帮助我吗?提前致谢
重要编辑: 我下载了Ubuntu,代码在那里运行顺利,没有任何问题。所以,要恢复
不知道为什么。
答案 0 :(得分:2)
您的问题可能是printf
输出被缓冲并在线程之间共享。在发布信号量之前,您必须确保用fflush
清空缓冲区。
答案 1 :(得分:1)
当您为sem_open()
致电sem2
时,会出现拼写错误 - 传入的姓名为"sem1"
:
sem1 = sem_open("sem1", O_CREAT, 0600, 0);
sem2 = sem_open("sem1", O_CREAT, 0600, 0);
// ^^^^
因此指针sem1
和sem2
将指向相同的信号量。
答案 2 :(得分:0)
Printf正在访问一个资源,即标准输出文件描述符。您需要一次锁定以允许仅通过一个线程访问stdout。否则,您可能会得到交错文本。我不确定你为什么要创建三个信号量,但考虑到如果你有多个信号量阻塞同一个资源,你就会有多个窗口打开该资源。如果你一次只关闭一个,那么你根本就不会阻止资源。
修改强>: 一个例子。线程1锁定sem 0,线程2等待。线程1解锁sem0,线程2可以继续。线程1现在锁定sem1。 他们都在写标准,但。这意味着他们两个,甚至服从你的锁,都被允许写入stdout。
为什么它不会提前发生只是由于线程争用。
编辑2 : 我认为约翰是正确的,因为我原来的解释不包括你的问题。我无法重现你的输出,我无法想象你输出的路径。即使有其他人提到的fflush示例,我仍然看不到即使使用相同的缓冲区以及信号量应该工作的方式,也会形成特定的字符串。我只能猜到这一点: