- 管道
匿名管道:用于父进程和子进程间的通信
有名管道:用于运行于同一系统中的任意两个进程间的通信
-消息队列
函数原型:
// 创建和获取 ipc 内核对象 --IPC_CREAT
int msgget(key_t key, int msgflag);
// 将消息发送到消息队列 --IPC_NOWAIT
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// 从消息队列获取消息 --IPC_NOWAIT/0
int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
// 查看、设置、删除 ipc 内核对象(用法和 shmctl 一样) 删除--IPC_RMID
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 共享内存
将两个进程不同的虚拟地址空间映射到一块相同的物理地址空间
函数原型:
//创建共享内存
int shmget(key_t key, size_t size, int shmflg);
//挂接共享内存
void *shmat(int shmid, const void *shmaddr, int shmflg);
//解除挂接共享内存
int shmdt(const void *shmaddr);
//销毁共享内存 删除--IPC_RMID
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 信号
使用举例:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
//信号处理函数
void signalHandler(int signum)
{
printf("Interrupt signal %d received\n",signum);
exit(signum);
}
int main(int argc,char argv[])
{
//信号处理函数绑定
signal(SIGINT,signalHandler);
int i = 1;
while (1)
{
printf("going to sleep %d...\n",i++);
if( i > 10 )
{
//主动发送信号
raise(SIGINT);
printf("send SIGINT\n");
}
sleep(1);
}
return 0;
}
信号发送与处理过程:
1.假设我们有一个进程 A,main 函数里面调用系统调用进入内核。
2.按照系统调用的原理,会将用户态栈的信息保存在 pt_regs 里面,记住原来用户态是运行到了 line A 的地方。
3.在内核中执行系统调用读取数据。
4.当发现没有什么数据可读取的时候,将进程状态设置为 TASK_INTERRUPTIBLE可中断的睡眠状态,让出 CPU,如果有信号来的话,是可以唤醒它的。
5.当给进程 A 发送一个信号,其实就是找到进程 A 的 task_struct,若信号值小于32为不可靠信号则加入信号集合(存在同个信号则忽略),若信号值大于32为可靠信号则加入信号链表。
6.当发现有信号到来的时候进程A被唤醒,返回用户态执行信号处理函数。
7.信号处理函数就执行完后,接着原本系统调用之后运行,当然这个系统调用返回的是它被中断导致没有执行完的错误。