C Semaphore奇怪的优先行为

时间:2015-06-20 01:10:20

标签: c concurrency semaphore

我在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,代码在那里运行顺利,没有任何问题。所以,要恢复

  • MacOSX 10.10.3 with Xcode 6.3.2 - &gt;不能正常工作
  • Ubuntu 15.04 - &gt;正常工作

不知道为什么。

3 个答案:

答案 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);
//               ^^^^

因此指针sem1sem2将指向相同的信号量。

答案 2 :(得分:0)

Printf正在访问一个资源,即标准输出文件描述符。您需要一次锁定以允许仅通过一个线程访问stdout。否则,您可能会得到交错文本。我不确定你为什么要创建三个信号量,但考虑到如果你有多个信号量阻塞同一个资源,你就会有多个窗口打开该资源。如果你一次只关闭一个,那么你根本就不会阻止资源。

修改: 一个例子。线程1锁定sem 0,线程2等待。线程1解锁sem0,线程2可以继续。线程1现在锁定sem1。 他们都在写标准,但。这意味着他们两个,甚至服从你的锁,都被允许写入stdout。

为什么它不会提前发生只是由于线程争用。

编辑2 : 我认为约翰是正确的,因为我原来的解释不包括你的问题。我无法重现你的输出,我无法想象你输出的路径。即使有其他人提到的fflush示例,我仍然看不到即使使用相同的缓冲区以及信号量应该工作的方式,也会形成特定的字符串。我只能猜到这一点:

  1. 您的信号量已命名,您不会销毁它们。这意味着它们会在您的程序调用之间持续存在。如果您在恰当的时间结束了程序,则信号量值可能处于您不期望的状态(如果信号量存在,它们将忽略sem_open的值参数)。 也许可能导致您的输出。
  2. 您没有检查sem函数的返回值,它们可以返回错误。在无效信号量上调用后续函数应立即返回,从而使您的printfs仅受到线程争用。