二进制信号量保持并发

Sem*_*ics 0 c multithreading posix semaphore

我试图使用二进制信号量实现一个多线程程序.这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

int g = 0;

sem_t *semaphore;

void *myThreadFun(void *vargp)
{
    int myid = (int)vargp;
    static int s = 0;
    sem_wait(semaphore);
    ++s; ++g;
    printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
    fflush(stdout);
    sem_post(semaphore);
    pthread_exit(0);
}

int main()
{   

    int i;
    pthread_t tid;
    if ((semaphore = sem_open("/semaphore", O_CREAT, 0644, 3))==SEM_FAILED) {
    printf("semaphore initialization failed\n");
    }


    for (i = 0; i < 3; i++) {
        pthread_create(&tid, NULL, myThreadFun, (void *)i);
    }

    pthread_exit(NULL);
    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

现在,当我打开sempahore时,我进行了计数3.我期待这不会起作用,我会得到竞争条件,因为每个线程现在都能够减少计数.

实施有什么问题吗?另外,如果我在sem_open期间使计数为0,则不会启动死锁条件,因为所有线程都应该在sem_wait上被阻塞.

Joh*_*ger 5

现在,当我打开sempahore时,我进行了计数3.我期待这不会起作用,我会得到竞争条件,因为每个线程现在都能够减少计数.

你怎么判断没有比赛?在没有数据竞争的情况下观察与您可以依赖的输出一致的输出并不能证明没有数据竞争.它只是没有提供任何证据.

但是,您似乎建议在多个线程中固有的数据竞争同时执行sem_wait()信号量,该信号量的值最初大于1(否则您在谈论哪个计数器?).但这完全是胡说八道.你在谈论信号量.这是一个同步对象.这些对象和操作它们的函数是线程同步的基础.它们本身要么完全是线程安全的,要么是最终的错误.

现在,你是正确的,你打开信号量的初始计数足以避免任何线程阻塞sem_wait(),因此它们都可以在整个身体中同时运行myThreadFun().但是,您还没有确定它们实际上同时运行的.他们可能没有这样做有几个原因.如果它们同时运行,则共享变量的递增sg非常担心的,但同样,即使你看不到任何数据争的迹象,这并不意味着没有一个.

其他一切不谈,事实上,你的线程所有的呼叫sem_wait(),sem_post()以及printf()诱导的记忆障碍等形式的同步,这将减少对观测异常效应的可能性sg. sem_wait()并且sem_post()必须包含才能正常工作,无论信号灯的当前计数的记忆障碍. printf()调用需要使用锁来保护流的状态免受多线程程序中的损坏,并且可以合理地假设这将需要内存屏障.

实施有什么问题吗?

是.它没有正确同步.使用计数1初始化信号量,以便仅在一个线程锁定信号量时修改sg发生.

另外,如果我在sem_open期间使计数为0,则不会启动死锁条件,因为所有线程都应该在sem_wait上被阻塞.

如果信号量在任何其他线程启动之前计数为0,则为是.因此,用计数0打开信号量是不合适的,除非您在启动线程之前随后发布信号量.但是您使用的是命名信号量.这些一直持续到删除,你永远不会删除它.sem_open()除非需要创建新的信号量,否则指定的计数无效; 当打开现有的信号量时,其计数不变.

此外,主线程在终止之前确实要加入所有其他线程.不这样做本身就没有错,但在大多数情况下,它是你想要的语义所必需的.

  • @Semantics,对于你没有阻塞的线程,你使用的是一个你永远不会删除的*命名*信号量.这样的信号量是持久的,所以你不断重新打开它.它的值仅在您创建时设置.我将在答案中澄清这一点. (2认同)