C - 用信号量同步多个孩子的优雅方式

Posted

技术标签:

【中文标题】C - 用信号量同步多个孩子的优雅方式【英文标题】:C - Elegant way to synchronise multiple children with semaphores 【发布时间】:2020-12-03 17:57:17 【问题描述】:

我想让 n 个孩子在信号量的帮助下同步地在屏幕上打印不同的字母。我用一个孩子加上父母和两个信号量做了这件事,但我真的没有看到一种优雅的方式来推广到 n 个孩子。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>

union semun 
    int val ;
    struct semid_ds * buf ;
    unsigned short * array ;
    struct seminfo * __buf ;
 ;

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

    int idsem;
    struct sembuf moins1sem1 [ 1 ] =   0, -1, 0   ;
    struct sembuf plus1sem1 [ 1 ] =   0, 1, 0   ;
    struct sembuf moins1sem2 [ 1 ] =   1, -1, 0   ;
    struct sembuf plus1sem2 [ 1 ] =   1, 1, 0   ;
    // key_t key = ftok("/etc/passwd",71); 
    // perror("Key");
    idsem = semget(IPC_PRIVATE, 4, IPC_CREAT|IPC_EXCL| 0600); //IPC_CREATE creates key if doesn't exist an EXCL fails if key exists
    //key is a "random" identifier for the sem and 1 is the nuber of sems we want to create 
    //Since we do not need to share the semaphore out of this process and its sons we can not use a key and instead provide the IPC_Private parameter
    perror("idsem");
    if(idsem == -1)
        semget(IPC_PRIVATE,4,0); //If it didn't work w/ flags try w/o
        perror("idsem2");
    
    else
        union semun semopts;
        semopts.val = 1; // We create an object to interact with the sem trough semctl
        semctl(idsem,0,SETVAL,semopts);//we set the value (SETVAL) of the first (0) sem in the group of semaphore of id idsem to the value field of semopts
        semopts.val = 0;
        semctl(idsem,1,SETVAL,semopts);
    
    switch (fork())
    
    case 0:
        for(int i=0;i<5;i++)
            semop(idsem,moins1sem1,1);
            fprintf(stderr,"Le fils dit A\n");
            semop(idsem,plus1sem2,1);
        
        break;
    
    default:
        for(int i=0;i<5;i++)
            semop(idsem,moins1sem2,1);
            fprintf(stderr,"Le pere dit B\n");
            semop(idsem,plus1sem1,1);
        
        break;
    
    
    return 0;

我们的想法是有一种方法来生成 n sembuf 并且有一个函数只将第 n 个操作应用于给定的信号量

我试图在一个数组中定义所有的操作

struct sembuf oparray [ 4 ] =  0, -1, 0 , 0, 1, 0 , 1, -1, 0 , 1, 1, 0  ;

并应用第 n 个操作

semop(idsem,oparray,n);

但它会将每个操作应用到 n 为止。

【问题讨论】:

semop(idsem,oparray,n); -> semop(idsem,&amp;oparray[n],1); ? 在这种情况下优雅是什么意思? 【参考方案1】:
semop(idsem,oparray,n);

[...] 将每个操作应用到 n 而不是 [nth]。

嗯,是的,这正是 semop() 被记录在案的。要仅应用索引n 处的操作,请使用

semop(idsem, oparray + n, 1);

或者,等价的,

semop(idsem, &oparray[n], 1);

还请记住,C 索引从零开始,因此第 nth 操作的索引是 n - 1

【讨论】:

以上是关于C - 用信号量同步多个孩子的优雅方式的主要内容,如果未能解决你的问题,请参考以下文章

μC/OS-II 信号量集

linux下,为了接收数据和解析数据同步进行,串口类中使用了信号量跟解析线程同步,多个串口实例会冲突吗

互斥锁和信号量

进程同步的几种方式

同步与锁

如何正确销毁 C 中多个进程使用的共享未命名信号量?