POSIX信号量:同步问题

3

我在使用Posix信号量进行同步时遇到了问题。这是我写的代码:

sem_t *sem1, *sem2;

void* test1() {
    int rv;

    while(1) {
        rv = sem_wait(sem1);
        printf("sem_wait(&sem1) = %d\n",rv);
        printf("test1\n");

        rv = sem_post(sem2);
        printf("sem_post(&sem2) = %d\n\n",rv);
    }
    return NULL;
}

void* test2() {

    while(1) {

        rv = sem_wait(sem2);
        printf("sem_wait(&sem2) = %d\n",rv);
        printf("test2\n");

        rv = sem_post(sem1);
        printf("sem_post(&sem1) = %d\n\n",rv);
    }
    return NULL;
}

int main (int argc, const char * argv[]) {

pthread_t t1,t2;

sem1 = sem_open("sem1", O_CREAT | O_EXCL, 0644, 1);

if (sem1 == SEM_FAILED){
    perror("sem1_init");
    sem_close(sem1);
    return;
}   

sem2 = sem_open("sem2", O_CREAT | O_EXCL, 0644, 0);
if (sem2 == SEM_FAILED){
    perror("sem2_init");
    sem_close(sem1);
    sem_close(sem2);
    return;
}

pthread_create(&t1, NULL, &test1, NULL);
pthread_create(&t2, NULL, &test2, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);

return 0;
}

我原以为,由于我将sem1初始化为1,将sem2初始化为0,test1将是第一个运行的函数,然后它们会交替进行直到时间结束。
但实际上这并没有发生。在日志中,我看到了很多次“test1”,很多次“test2”,有一段时间是交替进行的,然后又变得毫无秩序。 请问我的错误出在哪里?

ps. 不知道是否有用,但我正在运行MacOSX 10.6.7


编辑: 我更新了代码,删除了对sem_initsem_getvalue(在MacOS下都不存在)的所有调用,使用sem_open来初始化信号量,似乎可以工作。
然而,我发现一个奇怪的问题,可能是因为我对sem_open调用的误解:每次重新启动程序时,如果我重复使用相同的名称来指定信号量,则会收到错误“文件已存在”。我如何强制重用相同的标识符?

此外,根据人手册,sem_wait如果成功应返回0,如果失败则返回-1。如果我在test2中收到1,这是什么意思?


5
首先,启用编译警告并检查所有调用的返回值是否存在错误。然后,查看此类问题是否与您的问题相同:https://dev59.com/23M_5IYBdhLWcg3wWRuV 和 https://dev59.com/Y1HTa4cB1Zd3GeqPUMDt。 - nos
2
@nos 哇,如果我能给苹果一个-1分来表达他们没有实现这个功能的失望,我一定会这么做。 :P (当然,我同意:始终要检查错误...) - asveikau
1
asveikau 是正确的,似乎在 MacOS 下没有 sem_initsem_getvalue... 我本来期望至少会有一个警告,但实际上我甚至还收到了代码补全提示... 无论如何,我已经编辑了原帖并进行了一些更正。不确定这是否是问题的真正解决方案,但它似乎可以工作。请检查一下,看看是否有人知道我在帖子末尾添加的问题的答案。 - Manlio
1
@Summit Guy:如果他删除 O_EXCL,那么它将打开具有不确定起始值的现有信号量对象。 - Adam Rosenfield
1
@Saphrosit:您更新的代码对我来说运行良好(第一次运行)。 命名信号量在程序终止后仍然存在于内核中。 您需要调用sem_unlink来完全删除信号量。 如果您的程序仅由诸如Ctrl-C(SIGINT)之类的信号终止,则需要使用signal(2)sigaction(2)设置信号处理程序,该处理程序将在退出之前调用sem_unlink - Adam Rosenfield
显示剩余2条评论
1个回答

1
如果您希望这两个函数交替执行,您应该只使用一个信号量。
例如当其中一个线程t1被调度时,它会锁定sem1并保持它,并在while循环中运行直到被中断。因为它没有执行sem_post(&emp;sem1),所以它不会将控制权交给另一个线程。

更新:再看一遍,这段代码应该可以工作。我想在OSX上未实现sem_init可能是您的问题。


更新:回答你关于sem_wait返回1的问题,看起来真正的错误值是在errno中返回的。如果返回值!= 0,那么请检查这里。我猜测你看到的可能是EINTR。

完全不确定。当t1启动时,它调用sem_wait(&sem1)sem1被初始化为1,所以sem1的值被设置为0,t1进入关键部分(或者简单地跳过sem_wait调用)。它打印“test1”,然后sem_post(&sem2),将sem2的值设置为1(这样如果t2在信号量处等待,它就可以进入关键部分,否则它将在到达该点时进入)。当t1再次启动循环时,它会发现sem1为0(因为没有在sem1上调用sem_post),并开始等待信号量队列,直到t2解锁它。至少在理论上是这样。 - Manlio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接