我啥也不是奥,就是做个笔记要真看去看这几个大哥的:
https://blog.csdn.net/xiaonan153/article/details/81502245
https://www.cnblogs.com/zgq0/p/8780893.html
又发现个大哥这个全,太全了笔记都懒得记了:
[linux基础——linux进程间通信(IPC)机制总结]
管道
创建进程之前创建管道,
原型 :
#include <unistd.h>
int pipe(int fd[2]);
建立线程之后要关闭自己不用的那个:
close(fd[0]);
read和write 读写
fd[0]是读段
fd[1]是写段
FIFO
又名命名管道,是一种文件类型
特点
1.有名管道可以在无关进程间交换数据,这点无名管道做不到
2.有名管道有储存路径,他以一种特殊文件储存在系统文件中
原型
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode);
当 open 一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:
若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open 要阻塞到某个其他进程为读而打开它。
若指定了O_NONBLOCK,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。
消息队列
消息队列,是消息的连接表, 存放在内核中,一个消息队列由一个标识符(id)来标记
特点
1.消息队列是面向记录的,其中的消息具有特点的格式的优先级
2.消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按照类型读取
原型
#include <sys/msg.h>
//创建或者打开消息队列,成功返回队列id,失败返回-1
int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);
// 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
以下两种情况,msgget将创建一个新的消息队列:
如果没有key值对应的消息队列,并且flag中包含了IPC_CREAT标志位
key值参数为IPC_PRIVATE
函数msgrcv在读取消息1队列时,type参数有下面几种情况:
type == 0,返回队列中的第一个消息;
type > 0,返回队列中消息类型为 type 的第一个消息;
type < 0,返回队列中消息类型值小于或等于 type 绝对值的消息,如果有多个,则取类型值最小的消息。
可以看出,type值非 0 时用于以非先进先出次序读消息。也可以把 type 看做优先级的权值。
信号量
是一个计数器,用来控制进程间的互斥与同步,不是用来存储进程间的通信数据。
特点
1.信号量用于进程间同步,若在 进程间传递数据还需要共享内存
2.信号量基于操作系统的pv操作,程序多信号量的操作都是原子操作。
3.每次1对信号量的pv操作不仅限于对信号量值的加1或者减1,可以加减任意数。
4.支持信号量组
PV操作:一种实现进程互斥与同步的有效方法,包含P操作与V操作。
P操作:使 S=S-1 ,若 S>=0 ,则该进程继续执行,否则排入等待队列。
V操作:使 S=S+1 ,若 S>0 ,唤醒等待队列中的一个进程。
原子操作:原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始就直接运行结束,中间不会有任何切换操作。
原型
#include <sys/sem.h>
// 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
int semget(key_t key, int num_sems, int sem_flags);
// 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
int semop(int semid, struct sembuf semoparray[], size_t numops);
// 控制信号量的相关信息
int semctl(int semid, int sem_num, int cmd, ...);
当创建一个新的信号量集合是num_sems是集合中的信号量个数,当引用一个现有的集合,将num_senms指定为0;
例子
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/sem.h>
4
5 // 联合体,用于semctl初始化
6 union semun
7 {
8 int val; /*for SETVAL*/
9 struct semid_ds *buf;
10 unsigned short *array;
11 };
12
13 // 初始化信号量
14 int init_sem(int sem_id, int value)
15 {
16 union semun tmp;
17 tmp.val = value;
18 if(semctl(sem_id, 0, SETVAL, tmp) == -1)
19 {
20 perror("Init Semaphore Error");
21 return -1;
22 }
23 return 0;
24 }
25
26 // P操作:
27 // 若信号量值为1,获取资源并将信号量值-1
28 // 若信号量值为0,进程挂起等待
29 int sem_p(int sem_id)
30 {
31 struct sembuf sbuf;
32 sbuf.sem_num = 0; /*序号*/
33 sbuf.sem_op = -1; /*P操作*/
34 sbuf.sem_flg = SEM_UNDO;
35
36 if(semop(sem_id, &sbuf, 1) == -1)
37 {
38 perror("P operation Error");
39 return -1;
40 }
41 return 0;
42 }
43
44 // V操作:
45 // 释放资源并将信号量值+1
46 // 如果有进程正在挂起等待,则唤醒它们
47 int sem_v(int sem_id)
48 {
49 struct sembuf sbuf;
50 sbuf.sem_num = 0; /*序号*/
51 sbuf.sem_op = 1; /*V操作*/
52 sbuf.sem_flg = SEM_UNDO;
53
54 if(semop(sem_id, &sbuf, 1) == -1)
55 {
56 perror("V operation Error");
57 return -1;
58 }
59 return 0;
60 }
61
62 // 删除信号量集
63 int del_sem(int sem_id)
64 {
65 union semun tmp;
66 if(semctl(sem_id, 0, IPC_RMID, tmp) == -1)
67 {
68 perror("Delete Semaphore Error");
69 return -1;
70 }
71 return 0;
72 }
73
74
75 int main()
76 {
77 int sem_id; // 信号量集ID
78 key_t key;
79 pid_t pid;
80
81 // 获取key值
82 if((key = ftok(".", 'z')) < 0)
83 {
84 perror("ftok error");
85 exit(1);
86 }
87
88 // 创建信号量集,其中只有一个信号量
89 if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1)
90 {
91 perror("semget error");
92 exit(1);
93 }
94
95 // 初始化:初值设为0资源被占用
96 init_sem(sem_id, 0);
97
98 if((pid = fork()) == -1)
99 perror("Fork Error");
100 else if(pid == 0) /*子进程*/
101 {
102 sleep(2);
103 printf("Process child: pid=%d\n", getpid());
104 sem_v(sem_id); /*释放资源*/
105 }
106 else /*父进程*/
107 {
108 sem_p(sem_id); /*等待资源*/
109 printf("Process father: pid=%d\n", getpid());
110 sem_v(sem_id); /*释放资源*/
111 del_sem(sem_id); /*删除信号量集*/
112 }
113 return 0;
114 }
没仔细看就copy个例子以后看
共享内存
共享内存,指两个或多个进程共享一个给定的储存区
特点
1.共享内存是一种最快的ipc(进程间通讯)因为进程是直接对进程进行存取的。
2.因为多个进程可以同时操作所以需要进行同步。
3.信号量加共享内存经常结合在一起使用,信号量用来同步对共享内存的访问。
2.原型
1 #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);
当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。
当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。
信号
一、简述
记--进程之间使用信号进行通信。异步信号包含: 非实时信号 、实时信号。
实时信号一定会响应,非实时信息号不一定会响应(可能会被忽略,或丢失)
信号一般有以下设定:
1,捕捉 (收到某个信号,做指定的动作,而不是做默认的)
2,忽略 (收到某个信号,不做什么动作)
3,阻塞 (收到某个信号,先做完当前事情,然后在响应信号)
4,按照默认动作
注:SIGKILL,SIGSTOP不能被捕捉
二 。 信号函数signal()与kill()
signal()函数
功能 简单的信号处理函数(信号捕捉函数)
头文件 #include <signal.h>
原型
typedef void (*sighandler_t)(int); //信号处理函数的 指针
sighandler_t signal(int signum, sighandler_t handler);
参数
signum:要捕捉的信号
handler:处理方式
1、SIG_IGN:忽略这个信号
2、SIG_DFL:按照默认动作执行这个信号
3、如果是一个函数,则是捕捉这个信号,收到这个信号的时候去执行这个函数。
返回值
成功:返回信号处理程序的先前值
出错:返回SIG_ERR,并设置errno
kill()函数
功能 向一个进程发送信号
头文件 #include <sys/types.h>
#include <signal.h>
原型 int kill(pid_t pid, int sig);
参数
pid:进程ID (process id)
sig:要发送的信号
返回值
成功:返回0
失败:返回-1,并设置error。
套接字
流式套接字:提供可靠的,面向连接的通讯流
数据包套接字:定义一种无连接的服务,通过相互独立的报文进行传输,是无序的
原始套接字:用于新的网络协议的测试
总结
1.管道。速度慢容量有限,只能父子进程通讯
2。FIFO:任何进程间都能通讯,但是速度慢
3.消息队列 容量收到系统限制,且要注意第一次读的时候要考虑上一次没读完的数据
4.信号量,不能传递复杂消息只能用来同步。
5.共享内存,能控制容量速度快,但是要保持同步,共享内存可以进行线程间通信但是没必要