Linux进程信号量使用备忘

本文详细介绍了在Ubuntu环境下使用共享内存与信号量进行进程间通信的方法。包括信号量的创建、初始化、PV操作及销毁过程,并解释了关键属性的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不久前接了个外包,需要跟nodejs后端配合控制外设。
Ubuntu下访问设备需要sudo,然而后端程序员发现无法sudo调用我写的上位机程序,所以方案就改成了共享内存+信号量。
由于信号量这个我以前写过,以为不会有什么问题,但由于当时掌握不透彻,还是出现了很多莫名其妙的问题。百度了很多,发现网上错误的太多,以讹传讹的也数不胜数,所以下面写一下正确的方法。
首先介绍下用到的函数与结构。

函数:

int semget(key_t key,int nsems,int semflg);
int semctl(int semid,int semnum,int cmd, union semun arg);
int semop(int semid,struct sembuf *sops,size_t nsops);

  1. key_t key : 为信号量的Key,自己随意设定。int nsems :需要的信号量的数量。 int semflg : 创建信号量的方式等。
  2. int semid :为调用semget返回的值,标示信号量。int semnum : 信号量的下标,0号,1号等等,如果后面是SETALL的话此处会被忽略,填什么都不影响。如果后面填的是SETVAL,则会将对应下标的信号量设置为对应的值。 union semun arg : 初始化的参数,见下文。
  3. int semid : 同上。 struct sembuf *sops:对信号量所做的操作,见下文。size_t nsops : 操作信号量的个数,一般一次操作一个所以写1。

结构:

struct sembuf
{
  unsigned short int sem_num; /* semaphore number *//*想要操作的信号量下标*/
  short int sem_op;  /* semaphore operation *//*想要对信号量的操作,1为加1,-1为减1*/
  short int sem_flg;  /* operation flag *//*这里参数有两个,SEM_UNDO与一个IPC_NOWAIT*/
};
union semun 
{
    int val;/*设置单个信号量的值*/
    struct semid_ds *buf;
    unsigned short *array;/*设置多个信号量*/
};

我重点说下short int sem_flg这个属性。
SEM_UNDO,程序如果退出了,不管怎么退出,对信号量所有的操作都取消,但其他程序对信号量的操作不受影响。
IPC_NOWAIT,不会堵塞,信号量为0返回错误代码。
如果既不想用IPC_NOWAIT,也不想用SEM_UNDO,一定要将其设置为0,否则会有奇怪问题。

初始化代码:

void Process_Sem_FirstConfig()
{
    unsigned short array[2]={1,0};
    union semun sem_union;
    int ShareMem_Flag = semget(650, 2, 0666 |IPC_CREAT);//获取Key为650的两个信号量组,没有则创建一个,权限为0666
    sem_union.array = array;//初始化信号量组的初值,0号为1,1号为0
    semctl(ShareMem_Flag, 0, SETALL, sem_union);//设置信号量
}
//信号量第一次创建,若非第一次创建只需要调用semget(650, 2, 0666)获得信号量标示即可。
//千万不要再次调用semctl设置信号量初值

PV操作:

void Process_Sem_Wait(int Sem_ID, int Sem_Index)//(信号量标示,信号量组中信号量下标)
{
    struct sembuf sem_b;
    sem_b.sem_num = Sem_Index; /*id*/
    sem_b.sem_op = -1;         /* P operation*/
    sem_b.sem_flg = 0;
    semop(Sem_ID, &sem_b, 1);
}
void Process_Sem_Post(int Sem_ID, int Sem_Index)
{
    struct sembuf sem_b;
    sem_b.sem_num = Sem_Index; /* id */
    sem_b.sem_op = 1;  /* V operation */
    sem_b.sem_flg = 0;
    semop(Sem_ID, &sem_b, 1);
}

销毁信号量


void Process_Sem_Delete(int ShareMem_Flag)//信号量标示
{
    union semun sem_union;
    semctl(ShareMem_Flag, 0, IPC_RMID, sem_union);
    semctl(ShareMem_Flag, 1, IPC_RMID, sem_union);
}

倒是很简单,但如果研读不细的确很容易出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值