进程是设计和分析操作系统的有力工具。然而不同的进程之间.即使是具有家族联系的父子进程.都具有各自不同的进程映像。由于不同的进程运行在各自不同的内存空间中.一方对于变量的修改另一方是无法感知的,靠自己的空间无法资源共享,只能由系统单独提供,不同系统平台有不同方式。因此.进程之间的信息传递不可能通过变量或其它数据结构直接进行,只能通过进程间通信来完成。
进程间通信的方法有:
有名管道Pipe
无名管道fifo
共享内存shared memory
内存映射mmap
同步信号量semaphore
套接子socket
消息队列mesgq
管道
管道是由内核提供的空间,容量有限。读写的方向性:读走、写入。
一、无名管道
#include
int pipe(int pipefd[2]); //即两个值,代表读写
无名管道不对应文件类型,只存在于内存中,只能在亲缘进程间。文件标识符的打开关闭。安全性,资源分配合理调度。
过程:
1、内核给进程分配资源,读写指针分别指向读写两端。
2、fotk()后子进程也如此,读写指针指向读写两端。
3、一共4个指针,分别各关闭一个指针,让一个只写,让一个只读,形成管道。
注意:
1.必须是父子进程或亲缘进程。
2.所分配空间可能满,写等待,
3.等全读走(非读取!),再写。
二、有名管道
有名管道,文件类型p,无需父子进程,正经的管道文件。
在磁盘建立管道文件,但不存储数据,只起传递作用,让其他进程可以打开,可在任意进程间操作。数据进内核通过管道文件去到另一个文件。
读操作取决于管道内有无数据,有什么取走什么。先发先收。读写端都要存在,特别是写端一定存在。read()一读到EOF就退出。
写是主动的、有返回值的,内核回应直接关闭,写还有准备过程,如等待输入。
读是从属动作没有获得返回值,内核只会写不进、不会关闭,读是整体读取。
接受的人负责创建,管道文件一般大小都为0,并发让线程进程按角色分工。
创建管道文件
mkfifo test_file.fifo
#include
#include
int mkfifo(const char *pathname, mode_t mode);
三、共享内存
共享内存,效率最高,在内存中提供空间,两个进程同时映射,无需切换到内核态(不使用系统调用),没有额外的复制操作。本身无保护和互斥机制,无同步能力,配套使用同步的信号量,主要作用是同步,依然不能读取数据。
#include
#include
key_t ftok(const char *pathname, int proj_id);
pathname是指定路径,filename是指定的文件名,这个文件必须存在且可以访问。
id是子序号,它是一个8bit的整数。即范围是0~255。
当函数执行成功,则会返回key_t键值,否则返回-1。在一般的UNIX中,通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。
ftok根据路径名,提取文件信息,再根据这些文件信息及project ID合成key,该路径可以随便设置。但该路径是必须存在的,ftok只是根据文件inode在系统内的唯一性来取一个数值,和文件的权限无关。
分配
#include
#include
//得到一个共享内存标识符或创建一个共享内存对象
int shmget(key_t key, size_t size, int shmflg)
绑定
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
添加:内存拷贝函数
#include
void *memcpy(void *dest, const void *src, size_t n);
脱离
int shmdt(const void *shmaddr);
释放
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
此函数函数本身不仅仅用来删除,主要是用于控制。
shmctl(shmid, IPC_RMID, 0);
作用是从系统中删除该恭喜存储段。因为每个共享存储段有一个连接计数(shmid_ds结构中的shm_nattch),所以除非使用该段的最后一个进程终止与该段脱接,否则不会实际上删除该存储段。
Linux进程间通信(7)
四、同步信号量
#include
#include
#include
分配和销毁/获取和释放
int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
//根据cmd的值不同,传不同的值
等待和投递
int semop(int semid, struct sembuf *sops, unsigned nsops);
//第一个参数信号量集的id,参数二和参数三一起,结构体首地址和个数,成为结构体数组,
//每一个结构体对应一个操作,结构体首地址和个数。semop()对数组诸葛处理。
//当前信号量的值+op值,op<0对应wait,op>0对应post。
保护用锁,同步用信号量,异步用信号
共享内存,消息队列,信号量三者都是找一个中间介质,来进行通信的,系统资源很多,要找有“唯一属性”的,就是文件的设备编号和节点,它是唯一的,但是直接用它来作识别好像不太好,不过可以用它来产生一个号就是ftok()。