1. 共享内存
共享内存 - 内核管理一块物理内存,允许不同的进程访问,媒介就是 物理内存,最快的IPC。
编程步骤:
1 先获得key。
key_t key = ftok();
2 创建/获取内部ID。
int shmid = shmget(key,flags);
3 挂接(映射)共享内存 shmat(),返回首地址
4 使用共享内存
5 脱接共享内存(解除映射) shmdt()
6 如果不再使用,用 shmctl(IPC_RMID)删除
共享内存虽然最快,但有致命的弱点:多进程协调工作基本无法控制(比如:多进程写)。消息队列很好的解决了这个问题。
2. 消息队列
消息队列(重点) - 消息就是存放数据的单位。
在消息队列中,把需要交互的数据封存成一个消息,把消息放入队列中。每个进程都可以从队列中放入/取出消息。消息队列 比较快,以内存中的队列做媒介(内核管理)。
消息队列的使用步骤:
1 生成key。 - 头文件 或 ftok()
2 创建/获取 消息队列的ID。
int msgid = msgget(key,flags);
3 发送和接收消息,函数:
msgsnd(); - 发送
msgrcv(); - 接收
4 如果使用完毕,可以使用
msgctl(IPC_RMID)删除。
消息类型 :
消息分为无类型消息和有类型消息:
无类型消息:任意类型,比如:整数、字符串、浮点
有类型消息:必须是结构,而且结构的第一个成员必须是long,格式:
struct 名称{ //名称可以是任意标识符
long mtype;//消息类型
char buf[256];//任意类型 存储数据
};
消息类型必须大于0,因为 0 代表任意类型。
msgsnd(msgid,&msg,sizeof(数据),flags)
第二个参数&msg 就是 消息结构的指针
第三个参数是 数据的size,不包括类型的大小(如果包括也可以,但接受时也要包括)。
flags可以是0 - 阻塞,IPC_NOWAIT - 非阻塞
msgrcv(msgid,&msg,sizeof(数据),
long msgtype,flags)
接收无类型消息时,msgtype给0,代表任意类型。此时消息队列出队的方式就是 先入先出。
接收有类型消息时,msgtype可以是:
0 代表任意类型,效果和无类型一样先入先出
>0 代表对应类型,只有该类型的消息会出队,如果有多个相同类型的依然先入先出,如果没有对应类型的 阻塞/返回错误。
<0 接收小于等于msgtype的绝对值的消息,并且是从最小值到最大值的次序出队。
3. 信号量集:
信号量集 - XSI IPC的方式。但和共享内存、消息队列有很大的区别,信号量集 其实就是一个 信号量的数组。信号量(semaphore) 就是一个计数器。用于控制 访问同一资源的 最大并行(同时运行)进程数。当信号量到达0时,再有进程访问就会被阻塞,直到有其它进程释放信号量才能访问。
信号量的工作方式:先设成最大值,然后有进程访问就 -1 ,结束访问就 +1 ,当计数为0时,就阻塞或者返回错误(非阻塞方式),直到计数再次为正 为止。
IPC对应的是信号量集,而不是单个的信号量,即使只有一个信号量,也要做成长度为1的信号量集。
信号量集的编程步骤:
1 生成 key。
2 创建/获取 信号量集的 内部ID。
semget(key,数组长度,flags);
返回信号量集的ID
3 如果是新建信号量集,需要 设置每个信号量的初始值。
semctl(semid,下标,SETVAL,初始值);
设置某个信号量的初始值。
4 使用信号量集
5 如果不用了,可以删除 semctl(RMID)
如何使用信号量集:
semop()函数
int semop(int semid, struct sembuf
semoparray[],size_t nops);
参数semoparray是一个指针,它指向一个信号量操作数组,信号量操作由sembuf结构表示:
struct sembuf{
unsigned short sem_num;//信号量的下标
short sem_op; //信号量操作方式。-1,0,1
short sem_flg; //信号量的操作标记,默认为0,也可以用IPC_NOWAIT代表非阻塞
};