进程间通信的方式
匿名管道
- 半双工,具有固定的读端和写端,只能读取一次
- 只能用于有亲属关系的进程间通信
- 可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write函数。但是它不 是普通的文件,并不属于其他任何文件系统,只能用于内存中。
- Int pipe(int fd[2]);当一个管道建立时,会创建两个文件文件描述符,要关闭管道只需将这两 个文件描述符关闭即可
nt main(){
int fd[2];
int ret;
ret = pipe(fd);
if(ret==-1)perror("make pipe error:");
pid_t pid = fork();
if(pid==-1)perror("make pid error:");
else if(pid>0){
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ls","ls",NULL);
}else if(pid==0){
close(fd[1]);
dup2(fd[0],STDIN_FILENO);
execlp("Wc", "Wc", "-1",NULL);
}
命名管道
- 半双工,具有固定的读端与写端,只能读取一次
- 可以在无关的进程间进行通信
- FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中;FIFO在磁盘上没有数据块,文件仅仅是用来标识内核中的一条通道。
int mkfifo(const char* pathname, mode_t mode);
消息队列
- 消息队列,是消息的连接表,存放在内核中。一个消息队列由一个标识符来标识;
- 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级;
- 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除;
- 消息队列可以实现消息的随机查询
信号量
- 信号量是一个计数器,信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信 数据;
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存;
- 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作;
共享内存
- 共享内存,指两个或多个进程共享一个给定的存储区
- 共享内存是最快的一种进程通信方式,因为进程是直接对内存进行存取
- 因为多个进程可以同时操作,所以需要进行同步
原理
现代操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A 和 进程 B 的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。
共享内存的机制,就是各拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。
两种实现方式
int shmget(key_t key, size_t size, int shmflg);//创建共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);//挂接共享内存
int shmdt(const void *shmaddr);//取消关联共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);//销毁共享内存
套接字
此方法主要用于在客户端和服务器进程之间通过网络进行通信。也有本地套接字来完成本地进程间的通信
信号
- 信号其实就是一个软件中断。它由内核负责产生发送和处理。信号由终端或者进程调用系统函数产生。
- 信号有抵达和未决两种状态,未决的主要原因是信号阻塞。
- 信号处理方式主要有:
Linux内核的进程控制块PCB是一个结构体, task struct,除了包含进程id,状态,工作目录,用户id,组id, 文件描述符表,还包含了信号相关的信息,主要指阻塞信号集和未决信号集。
阻塞信号集(信号屏蔽字): 将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,该信号 的处理将推后(解除屏蔽后)
未决信号集: 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态。当信号被处理对应位翻 转回为0。这一时刻往往非常短暂。
两个不可被丢弃和捕捉的信号
- SIGKILL:无条件终止进程
- SIGSTOP:暂停进程执行
信号捕捉的两个函数
sighandler_t signal(int signum, sighandler_t handler);
//参数解释:
//signum:更改的信号值
//handler:函数指针,要更改的动作是什么
//实际上,该函数内部也调用了sigaction函数。
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//参数解释:
//signum:待更改的信号值
//void (*sa_handler)(int);//函数指针,保存了内核对信号的处理方式
//void (*sa_sigaction)(int, siginfo_t *, void *);//
//sigset_t sa_mask;//保存的是当进程在处理信号的时候,收到的信号
//int sa_flags;//SA_SIGINFO,OS在处理信号的时候,调用的就是sa_sigaction函数指针当中保存的值0,在处理信号的时候,调用sa_handler保存的函数
//void (*sa_restorer)(void);