进程间通信(IPC)

进程间通信(IPC)

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息.

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC

https://www.cnblogs.com/zgq0/p/8780893.html
文章

管道通信原理

一、管道

管道,通常指无名管道,是 UNIX 系统IPC最古老的形式。

1、特点:

  1. 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
  2. 它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
  3. 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的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,也称为命名管道,它是一种文件类型。

  1. FIFO可以在无关的进程之间交换数据,与无名管道不同。
  2. 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

共享内存概论

  • 无名管道
    男:放入纸条 女:拿入纸条
    只读不回
  • 命名管道
    男:放入纸条 女:拿入纸条
    只读不回
  • 消息队列
    男:将纸条放入箱子 女:将箱子纸条拿出来看,放回去
    相当于消息队列的纸箱还有纸条保留消息,除非把纸箱消息删除掉
    女:将纸条放入箱子 男:将箱子纸条拿出来看,放回去
    相当于消息队列的纸箱还有纸条保留消息,除非把纸箱消息删除掉
  • 共享内存
    内容直接写在纸条,两个用户都能看得到,共同使用一个共享内存
  • 信号
  • 信号量
  1. 因为多个进程可以同时操作,所以需要进行同步。
  2. 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
  3. 共享内存是最快的一种 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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值