1> 条件变量本质上也是一个临界资源,维护了一个队列,当消费者要想指向前,先进入等待队列中,直到生产者唤醒后,才能执行
2> 由于多个消费者线程要进入等待队列时,可能产生竞态,为了解决该竞态,同样要引入互斥机制
3> 条件变量表示一个生产者和多个消费者之间的同步关系,而消费者和消费者之间没有同步关系
创建条件变量
初始化条件变量
消费者线程进入等待队列
唤醒消费者线程
销毁条件变量
1> 多个线程之间的信息通信可以使用全局变量来完成,只需注意同步互斥机制即可
2> 多个进程之间的信息通信,不可用使用全局变量完成,因为多个进程之间用户空间是独立的,每个进程拥有自己的全局变量
3> 可以使用外部文件完成多个进程之间通信,一个进程向文件中写入数据,另一个进程从文件中读取数据。但是由于进程的调度是时间片轮询机制,不确定哪个进程先执行,所以该方案需要在多进程同步的基础上完成
4> 由于多个进程之间用户空间是独立的,但是内核空间是共享的,所以可以利用内核空间完成通信,一个进程向内核空间写入数据,另一个进程可以从内核空间取出数据
1、内核提供了三种通信方式:无名管道、有名管道、信号
2、System V提供了三种通信方式:消息队列、共享内存、信号量(信号灯集)
3、套接字通信
1> 在内核空间创建出一个特殊的文件(管道文件)
2> 对于管道文件中的数据操作是一次性的,当管道中的数据被读取后,就不存在了
3> 管道分为无名管道和有名管道:无名管道仅用于亲缘进程间的通信,而有名管道,既可以用于亲缘进程间通信,也可以用于非亲缘进程间通信
4> 管道的通信是半双工通信方式:
单工:只能A进程向B进程发送数据
半双工:同一时刻,只能A向B发数据或B向A发数据
全双工:同一时刻,AB进程可以互发消息
5> 管道遵循先进先出的原则:先写入的数据会先读取出来
6> 一个管道被打开后,会产生两端,分别是读端和写端,当两端全部都被关闭后,管道在内核中就消失了
7> 由于管道存在内核空间,对管道的操作只能使用系统调用(文件IO),而且不能使用lseek移动光标
1> 无名管道:顾名思义就是没有名字的管道,不存在于文件系统中,管道文件创建出来后,在内存中存放
2> 由于在内存中存放,没有文件系统中的名字,所以,一个进程创建出来的无名管道文件,其他进程是没有办法打开的,所以该方式不适用于非亲缘进程间通信
3> 无名管道,只适用于亲缘进程间通信,并且,需要在创建子进程之前将管道文件打开
4> 无名管道的api
#include
int pipe(int pipefd[2]);
5> 管道的特性
1、可以使用无名管道完成自己跟自己通信
2、管道的大小为:64K
3、管道的读写特点
当读端存在时:写管道有多少写多少,直到写满64k后,在write处阻塞
当读端不存在时:写管道写入数据后,会导致管道破裂
当写端存在时:读管道有多少读多少,没有数据的话,在read处阻塞
当写端不存在时:读管道有多少读多少,没有数据的话,不会在read处阻塞
1> 有名管道:顾名思义就是有名字的管道,存储在文件系统中
2> 有名管道的操作也是一次性的,数据被读取后,就没有了
3> 虽然存储在外部磁盘上,但是,不用于存储信息,只是用于进程间通信
4> 有名管道既可以用于亲缘进程间通信,也可以用于非亲缘进程间的通信
5> 有名管道的api5> 有名管道的api
#include
#include
int mkfifo(const char *pathname, mode_t mode);
1> 信号是软件模拟硬件中的中断,中断是硬件实现的,信号是软件实现的
2> 中断:停止当前正在进行的事情,去执行其他事情,执行结束后,继续执行自己的事
3> 一个进程可以给另一个进程发送信号;用户也可以给一个进程发送信号;内核可以向进程发送信号
4> 信号通信,属于异步通信:两个进程各干各的,互不影响
5> 信号处理方式:默认(一般是杀死进程)、忽略、捕获(捕获信号去做另一件事)
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
#include
int kill(pid_t pid, int sig);
#include
int raise(int sig);
1> 种类:
消息队列:在内核空间维护了一个队列,所有进程都可以向队列中存放数据,也可以从队列中取出数据
共享内存:将物理内存映射出来,共所有进程使用
信号量(信号灯集):主要完成进程的同步工作
2> 关于IPC的相关指令
ipcs: 查看所有IPC对象的详细信息
ipcs -q:只查看消息队列的详细信息
ipcs -m:只查看共享内存的详细信息
ipcs -s:只查看信号量的详细信息
ipcrm -q/-m/-s ID:表示删除指定的消息队列、共享内存、信号量
3> 关于系统5提供的进程间通信对象,都需要使用一个key值
消息队列的API
1、创建key值
2、创建消息队列
3、向消息队列中存放数据
4、从消息队列中取消息
5、消息队列的控制函数
1> 所谓共享内存,是将物理内存映射到不同的进程中,不同进程直接对映射出来的共享内存进行操作,无需进行用户空间和内核空间的切换
共享内存的相关API
1、创建key值
key_t ftok(const char *pathname, int proj_id);
2、申请物理内存,创建出共享内存段2、申请物理内存,创建出共享内存段
int shmget(key_t key, size_t size, int shmflg);
3、将共享内存映射到用户空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
4、取消共享内存的映射
int shmdt(const void *shmaddr);
5、共享内存的控制函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);