【回眸】技术干货——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!
