进程间通信(IPC)
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息.
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC
https://www.cnblogs.com/zgq0/p/8780893.html
文章
管道通信原理
一、管道
管道,通常指无名管道,是 UNIX 系统IPC最古老的形式。
1、特点:
- 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
- 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
- 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
管道就像水一样,从上流下去就没了。
2、原型:
1 #include <unistd.h>
2 int pipe(int fd[2]); // 返回值:若成功返回0,失败返回-1
当一个管道建立时,它会创建两个文件描述符:**fd[0]**为读而打开,**fd[1]**为写而打开。如下图:
要关闭管道只需将这两个文件描述符关闭即可。
man 2 read
读手册
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd[2];
pid_t pidl
char buf[128];
if(pipe(fd) == -1){
printf("creat pipe failed\n");
}
pid = fork();
if(pid < 0){
printf("creat child failed\n");
}
else if(pid > 0){
printf("this is father\n");
close(fd[0]);//关闭读
write(fd[1],"hello from father",strlen("hello from father"));//关闭写
wait(NULL);
}else{
printf("this is child\n");
close(fd[1]);//关闭写
read(fd[0],buf,128);
printf("read from father:%s\n",buf);
exit(0);
}
return 0;
}
输出结果:
this is father
this is child
read from father:hello from father
创建命名管道(FIFO)
FIFO,也称为命名管道,它是一种文件类型。
- FIFO可以在无关的进程之间交换数据,与无名管道不同。
- FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
1 #include <sys/stat.h>
2 // 返回值:成功返回0,出错返回-1
3 int mkfifo(const char *pathname, mode_t mode);
其中的 mode 参数与open函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。
当 open 一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:
- 若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open
要阻塞到某个其他进程为读而打开它。 - 若指定了O_NONBLOCK,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该
FIFO,其errno置ENXIO。
#include <sys/types.h>
#include <sys/stat.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
mkfifo("./file1",0600);//文件名,模式
return 0;
}
输出结果:
file1 文件会出现 prw,就是管道+可读+可写的意思
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
int ret = mkfifo("./file1",0600);//文件名,模式
if(ret == 0){
printf("mkfifo success");
}
if(ret == -1){
printf("mkfifo failed");
perror("why");
}
return 0;
}
输出结果:失败的可能原因是文件可能存在
mkfifo failed
why:File exists
优化
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
if((mkfifo("./file1",0600)==-1) && errno == EEXIST){//文件名,模式
printf("mkfifo failed");
perror("why");
}else{
if(errno == EEXIST){
printf("file exisit\n");
}else{
printf("mkfifo success\n");
}
}
return 0;
}
输出结果:
没有file文件 mkfifo success
有file文件 file exisit
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
if((mkfifo("./file1",0600)==-1) && errno == EEXIST){//文件名,模式
printf("mkfifo failed");
perror("why");
}
int fd = open("./file",O_RDONLY);
printf("open successful\n");
return 0;
}
gcc -o read
先运行./write
输出结果没有,为什么,只读 open 要阻塞到某个其他进程为写而打开此 FIFO。
被阻塞了
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
int fd = open("./file",O_WRONLY);
printf("write open successful\n");
return 0;
}
gcc -o write
先运行./read
在运行./read
输出结果:write open successful
下面是读
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
char buf[20] = {0};
if((mkfifo("./file1",0600)==-1) && errno == EEXIST){//文件名,模式
printf("mkfifo failed");
perror("why");
}
int fd = open("./file",O_RDONLY);
printf("open successful\n");
int n_read = read(fd,buf,20);
printf("read %d byte from fifo.context:%s\n",n_read,buf);
close(fd);
return 0;
}
下面是写
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
// int mkfifo(const char *pathname,mode_t mode);
int main()
{
char *str = "message from fifo";
int fd = open("./file",O_WRONLY);
printf("write open successful\n");
write(fd,str,strlen(str));
close(fd);
return 0;
}
Linux命令行:
./read
./write
write open successful
open successful
read 17 byte from fifo.context:message from fifo
打开命名管道,都是要阻塞,实现通信
消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
- 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
#include <sys/msg.h>
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);
4 // 添加消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 读取消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
在以下两种情况下,msgget将创建一个新的消息队列:
如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREA标志位。key参数为IPC_PRIVATE。
函数msgrcv在读取消息队列时,type参数有下面几种情况:
- type == 0,返回队列中的第一个消息;
- type > 0,返回队列中消息类型为 type 的第一个消息;
- type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。(其他的参数解释,请自行Google之)
下面是接受
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
int mgsid = msgget(0x1234,IPC_CREA|0777);//0777可读可写可执行
if(mgsid == -1){
printf("get que faile\n");
}
msgrcv(msqid, &readBuf,sizeof(readBuf.ntxte),888,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("read from que :%s\n",readBuf,ntext):
return 0;
}
Linux命令行:gcc -o get
下面是发送
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf sendBuf = {888,"this is message from quen"};
int mgsid = msgget(0x1234,IPC_CREA|0777);//0777可读可写可执行
if(mgsid == -1){
printf("get que faile\n");
}
//msgrcv(msqid, &readBuf,sizeof(readBuf.ntxte),888,0);//队列,消息,长度,类型,判断,,888一直堵塞
msgsnd(mgsid, &sendBuf,strlen(sendBuf.ntxte),0);
return 0;
}
./get 一直等着
./send 就发送
输出结果:this is message from quen
Linux命令行输入:vimdiff msgGet.c msgSend.c // 对比两个代码
下面是双方互发消息
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {888,"this is message from quen"};
int mgsid = msgget(0x1235,IPC_CREA|0777);//队列,模式 0777可读可写可执行
if(mgsid == -1){
printf("get que faile\n");
}
/*888 发送数据*/
msgsnd(msqid, &sendBuf,strlen(sendBuf.ntxte),0);
printf("send over\n");
/*下面是接受数据*/
msgrcv(mgsid, &readBuf,sizeof(readBuf.ntxte),988,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("return from get:%s\n",readBuf,ntext):
return 0;
}
./get
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {988,"thank for you for reach"};
int mgsid = msgget(0x1235,IPC_CREA|0777);//0777可读可写可执行 0x1235 是因为0x1234之前有这个队列了
if(mgsid == -1){
printf("get que faile\n");
}
/*888 接收数据*/
msgrcv(msqid, &readBuf,sizeof(readBuf.ntxte),888,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("read from que:%s\n",readBuf.ntext);
msgsnd(mgsid, &sendBuf,strlen(sendBuf.ntxte),0);
return 0;
}
./sent
Linux命令行:history //查你用的历史指令
./get
./send
输出结果:
send over
return from get:thank for you for reach
read from que:this is message from quen
键值生成及消息队列移除
ftok
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
在Linux命令行:ls -ai
可以看到文件
双方互相key查找KEY的值
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {888,"this is message from quen"};
key_t ket;
key = fotk(".",'z');//十六进制
printf("key = %x\n",key);
int mgsid = msgget(0x1235,IPC_CREA|0777);//队列,模式 0777可读可写可执行
if(mgsid == -1){
printf("get que faile\n");
}
/*888 发送数据*/
msgsnd(msqid, &sendBuf,strlen(sendBuf.ntxte),0);
printf("send over\n");
/*下面是接受数据*/
msgrcv(mgsid, &readBuf,sizeof(readBuf.ntxte),988,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("return from get:%s\n",readBuf,ntext):
return 0;
}
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {988,"thank for you for reach"};
key_t ket;
key = fotk(".",'z');//十六进制
printf("key = %x\n",key);
int mgsid = msgget(0x1235,IPC_CREA|0777);//0777可读可写可执行 0x1235 是因为0x1234之前有这个队列了
if(mgsid == -1){
printf("get que faile\n");
}
/*888 接收数据*/
msgrcv(msqid, &readBuf,sizeof(readBuf.ntxte),888,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("read from que:%s\n",readBuf.ntext);
msgsnd(mgsid, &sendBuf,strlen(sendBuf.ntxte),0);
return 0;
}
./get key = 7a0564d9
./send key = 7a0564d9
输出结果:
send over
return from get:thank for you for reach
read from que:this is message from quen
*// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds buf);
用完这个队列,就把这个队列消失
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {888,"this is message from quen"};
key_t ket;
key = fotk(".",'z');//十六进制
printf("key = %x\n",key);
int mgsid = msgget(0x1235,IPC_CREA|0777);//队列,模式 0777可读可写可执行
if(mgsid == -1){
printf("get que faile\n");
}
/*888 发送数据*/
msgsnd(msqid, &sendBuf,strlen(sendBuf.ntxte),0);
printf("send over\n");
/*下面是接受数据*/
msgrcv(mgsid, &readBuf,sizeof(readBuf.ntxte),988,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("return from get:%s\n",readBuf,ntext):
msgctl(mgsid,IPC_RMID,NULL);
return 0;
}
#include <stdio.h>
#include <sys/msg.h>
#include <sys/tpc.h>
#include <sys/msg.h>
#include <string.h>
// int msgget(key_t key, int flag)
struct msgbuf{
long ntype;
char ntext[128];
};
int main()
{
struct msgbuf readBuf;
struct msgbuf sendBuf = {988,"thank for you for reach"};
key_t ket;
key = fotk(".",'z');//十六进制
printf("key = %x\n",key);
int mgsid = msgget(0x1235,IPC_CREA|0777);//0777可读可写可执行 0x1235 是因为0x1234之前有这个队列了
if(mgsid == -1){
printf("get que faile\n");
}
/*888 接收数据*/
msgrcv(msqid, &readBuf,sizeof(readBuf.ntxte),888,0);//队列,消息,长度,类型,判断,,888一直堵塞
printf("read from que:%s\n",readBuf.ntext);
msgsnd(mgsid, &sendBuf,strlen(sendBuf.ntxte),0);
msgctl(mgsid,IPC_RMID,NULL);
return 0;
}
./get key = 7a0564d9
./send key = 7a0564d9
输出结果:
send over
return from get:thank for you for reach
read from que:this is message from quen
共享内存概论
- 无名管道
男:放入纸条 女:拿入纸条
只读不回 - 命名管道
男:放入纸条 女:拿入纸条
只读不回 - 消息队列
男:将纸条放入箱子 女:将箱子纸条拿出来看,放回去
相当于消息队列的纸箱还有纸条保留消息,除非把纸箱消息删除掉
女:将纸条放入箱子 男:将箱子纸条拿出来看,放回去
相当于消息队列的纸箱还有纸条保留消息,除非把纸箱消息删除掉 - 共享内存
内容直接写在纸条,两个用户都能看得到,共同使用一个共享内存 - 信号
- 信号量
- 因为多个进程可以同时操作,所以需要进行同步。
- 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
- 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
共享内存编程
(1)创建共享内存shget(2)映射 shmat(3)数据(4)释放共享内存shmdt(5)控制(干掉)shmctl
https://blog.csdn.net/ypt523/article/details/79958188
#include <sys/shm.h>
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);
4 // 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);
6 // 断开与共享内存的连接:成功返回0,失败返回-1
7 int shmdt(void *addr);
8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
下面是写
#include <sys/ipc.h>
#include <sys/shn.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int flag);
int main()
{
key_t key;
key = fotk(".",1);
char *shmaddr;
int shm_id= shmget(key, 1024*4, CREAT|0666);
if(shm_id== -1){
printf("shmget fail\n");
exit(-1);
}
shmaddr = shmat(shm_id, 0, 0);
printf("shmat ok\n");
strcpy(shmaddr ,"sudu");
sleep(5);
//int shmdt(void *addr);
shmdt(shmaddr);
//int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
shmctl(shm_id, IPC_RMID, 0);
printf("quit\n");
return 0;
}
两个代码执行,输出结果:
shmat ok
quit
下面是读
#include <sys/ipc.h>
#include <sys/shn.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int flag);
int main()
{
key_t key;
key = fotk(".",1);
char *shmaddr;
int shm_id= shmget(key, 1024*4, 0);
if(shm_id== -1){
printf("shmget fail\n");
exit(-1);
}
shmaddr = shmat(shm_id, 0, 0);
printf("shmat ok\n");
printf("data:%s\n",shmaddr );
//int shmdt(void *addr);
shmdt(shmaddr);
printf("quit\n");
return 0;
}
两个代码执行,输出结果:
shmat ok
sudu
quit
创建共享内存
#include <sys/ipc.h>
#include <sys/shn.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int flag);
int main()
{
key_t key;
key = fotk(".",1);
char *shmaddr;
int shm_id= shmget(key, 1024*4, CREAT|0666);
if(shm_id== -1){
printf("shmget fail\n");
exit(-1);
}
exit(0);
shmaddr = shmat(shm_id, 0, 0);
printf("shmat ok\n");
strcpy(shmaddr ,"sudu");
sleep(5);
//int shmdt(void *addr);
shmdt(shmaddr);
//int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
shmctl(shm_id, IPC_RMID, 0);
printf("quit\n");
return 0;
}
如何查看系统有多少共享内存
Linux指令:ipcs -m
信号
类似 敲门->开门 或者 手机响了->打开
博文 http://gityuan.com/2015/12/20/signal/
https://blog.csdn.net/w903414/article/details/109802539
Linux命令行 :kill -l ///信号
man 7 signal//查看手册
假设执行./a.out
Linux命令行:ps aux|grep a.out //出现4220
Linux命令行:kill -9 4220 //执行关闭
信号编程
软件编程出来的
#include <signal.h>
#include <stdio.h>
void handler(int signum)
{
printf("get signum=%d\n",signum)
printf("never quit\n");
}
int mian()
{
signal(SIGINT,handler);
while(1);
return 0;
}
输出结果:
^c get signum = 2
never quit
杀不死程序
只能用假设执行./a.out
Linux命令行:ps aux|grep a.out //出现4220
Linux命令行:kill -9 4220 //执行关闭
#include <signal.h>
#include <stdio.h>
void handler(int signum)
{
printf("get signum=%d\n",signum)
switch(signum){
case 2:printf("SIGINT\n");break;
case 9:printf("SIGILL\n");break;
case 10:printf("SIGUSR1\n");break;
}
}
int mian()
{
signal(SIGINT,handler);
signal(SIGKILL,handler);
signal(SIGUSR1,handler);
while(1);
return 0;
}
输出结果:
^c get signum = 2
never quit
杀不死程序
只能用假设执行./a.out
Linux命令行:ps aux|grep a.out //出现4220
Linux命令行:kill -9 4220 //执行关闭
输出结果:
^c get signum = 2
never quit
杀不死程序
只能用假设执行./a.out
Linux命令行:ps aux|grep a.out //出现4220
Linux命令行:kill -9 4220 //执行关闭
在这个基础上
^c get signum = 2
never quit
SIGUSR1
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
int main(int argc,char **argv)
{
int signum;
int pid;
signum = atoi(argv[1]);
pid = atoi(argv[2]);
printf("num:%d,pid =%d\n",signum,pid);
kill(pid,signum);
printf("send signal ok\n");
return 0;
}
gcc a.c -o pro
./pro
运行起来不懂
Linux命令行:ps aux|grep a.out //出现4220
在执行:./a.out 9 4220
就会出现Killed
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
int main(int argc,char **argv)
{
int signum;
int pid;
char cmd[128] = {0};
signum = atoi(argv[1]);//atoi转换为整型值
pid = atoi(argv[2]);
printf("num:%d,pid =%d\n",signum,pid);
sprintf(cmd,"kill -%d %d",signum,pid);
system(cmd);
printf("send signal ok\n");
return 0;
}
ps aux|grep a.out //出现4719
./a.out 9 4719 //杀死
忽略信号
#include <signal.h>
#include <stdio.h>
void handler(int signum)
{
printf("get signum=%d\n",signum)
switch(signum){
case 2:printf("SIGINT\n");break;
case 9:printf("SIGILL\n");break;
case 10:printf("SIGUSR1\n");break;
}
}
int mian()
{
signal(SIGINT,SIG_IGN);
signal(SIGKILL,SIG_IGN);
signal(SIGUSR1,handler);
while(1);
return 0;
}
信号如何携带消息
https://www.jianshu.com/p/f445bfeea40a
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用
sigset_t sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
int sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据
};
//回调函数句柄sa_handler、sa_sigaction只能任选其一
收信息
#include <signal.h>
#include <stdio.h>
//int sigaction(int signum, const struct sigaction *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);//info.si_int信息
printf("get data = %d\n",info->si_value.sival_int);//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;
}
Linux命令行./pro
pid = 5434
发信息
#include <stdio.h>
#include <signal.h>
int main(int argc,char **argv)
{
int signum;
int pid;
signum = atoi(argv[1]);
pid = atoi(argv[2]);
union sigval val;
val.sival_int = 100;
sigqueue(pid,signum,value);
printf("%d,done\n",getpid());
return 0;
}
ps aux |grep pro //5434
pid = 5434
./send 10 5434
就会发送get signum 10
get data = 100
get data = 100
from:5436
信号量
就是共享内存上了锁
要有钥匙:信号量
房间:临界资源
多道程序系统中存在许多进程,它们共享各种资源,然而有很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。许多物理设备都属于临界资源,如输入机、打印机、磁带机等。
信号量集:Linux
p操作:拿锁
v操作:放回锁
https://blog.csdn.net/chenpuo/article/details/81183678
原型
1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);
下面不知道父进程与子进程谁先运行
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// 联合体,用于semctl初始化
union semun
{
int val; /*for SETVAL*/
struct semid_ds *buf;
unsigned short *array;
};
int main(int argc,char const **argv)
{
key_t key;
key = ftok(".",2);
int semid;
//信号量集合会有一个信号量
semid = semget(key, 1,IPC_CREAT|0666);//获取/创建信号量
union semun initsem;
initsem.val = 1;//1把锁
//操作第0个信号量
semctl(semid, 0, SETVAL, initsem);//初始化信号量
//SETVAL设置信号量的值,设为为inisem
int pid = fork();
if(pid > 0){
//去拿锁
printf("this is father \n");
//锁放回去
}else if(pid == 0){
printf("this is child\n");
}else{
printf("fork error\n");
}
return 0;
}
cp /mnt/hgfs/os/demo 分开 //复制文件到这个文件
输出结果:
this is father
this is child
多次输出结果this is father 运行的比较多
下面让子进程先运行
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// 联合体,用于semctl初始化
union semun
{
int val; /*for SETVAL*/
struct semid_ds *buf;
unsigned short *array;
};
/*P操作*/
void pGetKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = -1;
set.sem_flag = SEM_UNDO;
semop(id,&set,1);
printf("get key\n");
}
/**v操作*/
void vPutkey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = 1;
set.sem_flag = SEM_UNDO;
semop(id,&set,1);
printf("put back key\n");
}
int main(int argc,char const **argv)
{
key_t key;
key = ftok(".",2);
int semid;
//信号量集合会有一个信号量
semid = semget(key, 1,IPC_CREAT|0666);//获取/创建信号量
union semun initsem;
initsem.val = 0;//1把锁 0就无锁的
//操作第0个信号量
semctl(semid, 0, SETVAL, initsem);//初始化信号量
//SETVAL设置信号量的值,设为为inisem
int pid = fork();
if(pid > 0){
//去拿锁
pGetKey(semid);
printf("this is father \n");
//锁放回去
vPutkey(semid);
//销毁锁
semctl(semid,0,IPC_RMID);//第0个信号量,摧毁
}else if(pid == 0){
printf("this is child\n");
vPutkey(semid);
}else{
printf("fork error\n");
}
return 0;
}
输出结果:
this is child
put back key
get key
this is father
put back key