进程间通讯(IPC)之信号量

信号量与其他IPC方式不同,它不是进行消息的交互,而是从当一个计数器的功能,它用于实现进程间的互斥和同步。(给我的感觉是有点像JAVA中线程的🔒)

举一个例子:两个人想要进入同一个密室去处理一些事情,钥匙也只有一把,每次只能有一个人拿一把钥匙进入密室。第一个人拿着钥匙进入密室,第二个人只能在外边等待,直到第一个人拿着钥匙出来之后,放回钥匙,才能进入密室处理自己的事情。信号量在这个过程中就充当着钥匙的作用,而密室则是充当临界资源的角色

特点:

  1. 信号量用于进程间的同步,若要在进程间传递数据需要结合共享内存使用
  2. 信号量基于操作系统的P(拿🔒)V(放回🔒)操作,程序对信号量的操作都是原子操作
  3. 每次对信号量的PV操作不仅限于对信号量的+1或-1操作,可以加减任何正整数
  4. 支持信号量组(多把🔑)

原型:

#include <sys/sem.h>

int semget(key_t ket,int num_sems,int sem_flags);
//创建或获取一个信号量组:成功返回信号量集的ID,失败返回-1
int semop(int semid,struct sembuf semoparray[],size_t numops);
//对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
int semctl(int semid,int sem_num,int cmd,...)
//控制信号量的相关信息

demo:

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

//int semget(key_t key, int nsems, int semflg);
//int semop(int semid, struct sembuf *sops, size_t nsops(几个信号量));
//int semctl(int semid, int semnum, int cmd, ...);

union semun {                                                                                                                                                   
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                            (Linux-specific) */
};
//P操作
void pGetKey(int id){
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op--; 
    buf.sem_flg = SEM_UNDO;
    semop(id,&buf,1);
    printf("Get key successfully!\n");
    return;
}
//V操作:
void vPutBackKey(int id){
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op++; 
    buf.sem_flg = SEM_UNDO;
    semop(id,&buf,1);
    printf("Put back key successfully!\n");
    return;
}
 
int main(){
    int pid;
    key_t key;
    key = ftok(".",5);
    
    union semun cmdinit;
    cmdinit.val = 0;

    int semid = semget(key,1,IPC_CREAT|0666);
    printf("semid = %d\n",semid);
    if(semctl(semid,0,SETVAL,cmdinit) == 0){
    //SETVAL是初始化信号量
        printf("Semctl success!\n");
    }else{
        printf("Semctl failure\n");
        perror("Why");
    } 
    pid = fork();
    if(pid > 0){
        pGetKey(semid);
        printf("This is father:\n");
        //pGetKey(semid);
        vPutBackKey(semid);
        semctl(semid,0,IPC_RMID);
        //移除当前信号量
    }else if(pid == 0){
        printf("This is son:\n");
        vPutBackKey(semid);
    }else{
        printf("Fork error!\n");
    }
    return 0;
}                                                  

运行结果:
在这里插入图片描述
semid为0有可能是ftok时数字可能在以前的进程中有重复
该程序的整体思路就是 先semget获取信号量的id方便进行操作,用semctl来初始化锁的相关信息(SETVAL),此时semctl就需要第四个参数(一个联合体),随后定义PV操作的函数(先初始化结构体,然后semop信号量),最后根据需求来semop控制进程谁先进行,谁后执行。

信号量常和共享内存当配使用,后续demo等写出来之后再放出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值