【回眸】技术干货——Linux 内核 (十五)进程间通讯 之 信号量

前言

上一篇文章介绍的共享内存有局限性,如:同步与互斥问题、内存管理复杂性问题、数据结构限制问题、可移植性差问题、调试困难问题。本篇博文介绍的信号量能够解决第一个同步与互斥问题。

信号量概念

信号量本质上是一个计数器(不设置全局变量是因为进程间是相互独立的,而这不一定能看到,看到也不能保证++引用计数为原子操作),用于多进程对共享数据对象的读取,它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享,解决了互斥问题。

信号量常用API

1.创建/获取一个信号量

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//创建/获取一个信号量,成功返回信号量ID,失败返回-1
int semget(key_t key, int nsems, int semflg);

2.改变信号量的值

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//成功返回0,失败返回-1
int semop(int semid, struct sembuf *sops, size_t nsops);

struct sembuf{
    short sem_num;				//除非使用一组信号量,否则它为0
    short sem_op;				//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
                    			//一个是+1,即V(发送信号)操作。
    short sem_flg;				//通常为SEM_UNDO,使操作系统跟踪信号,
                    			//并在进程没有释放该信号量而终止时,操作系统释放信号量
};

3. 控制信号量

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//成功返回非0值,失败返回-1
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) */
           };

信号量函数调用

comm9.c(接收操作)

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

//int sigaction(int signum, const struct signaction *act, struct sigaction *oldact);

void handler(int signum, siginfo_t *info,void *context){
printf("get signum %d\n",signum);
if (context != NULL){
printf("get data = %d\n",info->si_int);
printf("get data = %d\n",info->si_value.sival_int);
printf("from = %d\n",info->si_pid);

}
}
int main(){
struct sigaction act;
printf("pid = %d\n",getpid());
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;


sigaction(SIGUSR1,&act,NULL);

while (1);
return 0;
}

comm10.c(发送操作)

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
// int sigqueue(pid_t pid, int sig,const union sigval value);

int main(int argc,char **argv){

int signum;
int pid;
signum = atoi(argv[1]);
pid = atoi(argv[2]);
union sigval value;
value.sival_int = 100;
sigqueue(pid, signum,value);
printf("pid = %d,done.\n",getpid());
return 0;

}

运行结果展示

注意:这里编译完后,需要先运行comm9.c(接收)后运行comm10.c(发送)

后记碎碎念

Linux内核是一个系列,可以点击专栏查看同系列的其他文章,希望能帮到屏幕前的每一位应届生往届生,该博文最初发表在CSDN上。

#校招求职有谈薪空间吗##找工作前vs找工作后的心路变化##租房前辈的忠告##职场中你干过哪些“蠢”事##26届秋招投递记录#
应届生必学实用物联网技术 文章被收录于专栏

本专栏助应届生从物联网小白成长为企业争抢的技术人才,聚焦三大核心技术:传感器应用(环境监测)、嵌入式开发(STM32/Arduino)、通信协议(LoRa/NB-IoT/MQTT),配合10+实战项目(如智能温湿度监控系统)积累项目经验。覆盖智能硬件、工业物联网、智能家居领域岗位需求,解析企业招聘技术重点与面试题,帮电子、计算机、自动化等专业学生构建知识体系,提前锁定名企Offer!

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务