一 管道技术
1)概念
历史上是半双工的,只能单向流动,目前有系统提供全双工管道
linux上全双工管道由unix域套接字实现
只能在具有公共祖先的进程间使用
2)shell 中的命令序列 中 标准输入输出的重定向就是通过管道连接的
3)创建管道
pipe(int fields[2])
返回: fields[0]为读描述符,fields[1]为写描述符
fields[0]的数据来源于fields[1]
4)fstat函数对文件描述符返回fifo类型
5)由于某些系统不支持全双工管道,所以创建管道之后,需要将某些管道描述符关闭以用单向的管道
6)读写规则
当读一个写端已经关闭的管道,在所有数据读完之后,read返回0
当写一个读端已经关闭的管道,则产生信号SIGPIPE,忽略信号或者从信号处理函数返回后,write返回-1,errno =EPIPE
7)管道的最大值
fpathconf,pathconf返回PIPE_BUF的值
二 popen与pclose技术 (pipe open, pipe close)
目的:执行一个程序获得其输出,或者向一个进程写入东西
1)来自于标准IO库
file* popen(const char * cmdstring, const char * type)
pclose(file *)
2) popen执行fork,然后exec cmdstring,并且返回一个标准io文件指针
type : "r" 文件指针连接到exec进程的标准输出
: "w" 文件指针连接到exec进程的标准输入
3)标准输出通常是行缓冲的,如果不包含换行符,需要再调用fflush函数冲洗到屏幕
三 协同进程
目的:比popen更强,popen只能单边读或单边写入目的进程
协同进程可以向一个进程读写
概念: 当一个程序产生某个过滤程序的输入,同时又读取过滤程序的输出,则该过滤程序被成为协同进程 coprocess
四 FIFO命名管道
可用于不相关的进程
1)创建命名管道
mkfifo(const char*, mode_t mode)
2)mode需要区分O_NONBLOCK O_BLOCK
如果没有指定非阻塞模式: 写管道的进程会阻塞到相对应的读管道的进程, 读管道的进程会阻塞到写管道的进程
如果指定了阻塞模式,读操作会立即返回, 如果没有读管道的操作,写管道的进程会直接返回错误
3)写一个没有绑定读进程的管道,会产生信号SIGPIPE
4)FIFO的最大数据量是PIPE_BUF
5)命名管道的2个用处:
a) shell命令中,无需临时文件,将数据从1条管道线发送到另外1条管道线
b) 用于在客户端和服务器之间传送数据
五 三种XSI IPC
1)消息队列
2)信号量
3)共享存储
4)标识符是ipc对象内部名,键key与每个ipc对象关联,键作为外部名
5)键的数据类型key_t
6)创建ipc结构的方法 msgget semget shmget
7)ftok将路径及id 转换成唯一的键名
8)ipc结构体里面存有类型ipc_perm,该类型规定了权限和所有者
9)可以通过msgctl,semctrl,shmctrl来修改ipc结构体的权限
10)IPC的缺点:
创建了需要显示的去读取或删除数据,否则一直存在
ipc结构在文件系统中没有名字,不支持参加的文件命令
ipc不使用文件描述符,所以不能使用轮询,一次使用处理多个ipc结构
六 消息队列
1)概念 消息的链接表, queue, 标识符为queue id
2)创建或打开一个新的队列 msgget(key_t key, int flag),返回队列ID
3)追加消息到队列尾部
msgsnd(int msqid, const void* ptr, size_t nbytes, int flag)
消息内容结构体 struct mymesg
flag : IPC_NOWAIT 如果消息队列已满,则立即出错返回
没有指定IPC_NOWAIT 进程被阻塞,直到有空间,系统删除了队列,捕捉到一个信号,并从信号处理程序返回
4)消息内容: 类型字段 + 长度 + 内容
5)取出消息 msgrcv 可以按先进先出或者消息的类型2种方式取消息
msgrcv(int msqid, void* ptr, size_t nbytes, long type, int flag)
参数flag设置了MSG_NOERROR 而消息长度大于了nbytes 则消息被截断返回,
否则返回E2BIG,消息不取出来
参数type指定了想要那一种消息
type ==0 返回队列中的第一个消息
type>0 返回队列中消息类型为type的第一个消息
type <0 返回消息类型小于或等于type绝对值的消息中的最小值的消息
6)队列的当前状态 struct msqid_ds
7)消息队列控制函数msgctrl(int msqid, int cmd, struct msqid_ds* buf)
cmd 说明
IPC_STAT 取消息队列的msqid_ds结构
IPC_SET 设置buf为消息队列的msqid_ds结构
IPC_RMID 删除消息队列及其队列中的数据
**由于消息队列具有的问题,所以apue里面推荐不要在应用程序里面使用
七 信号量(semaphore)
1)概念: 用于多进程对共享数据访问的一个计数器
2)获得共享资源的步骤:
a)测试控制该资源的信号量
b)新信号量的值为正,则进程可以使用该资源,进程将信号量减1,表示它正在使用
c)若信号量的值为0,则进程进入休眠状态
d)进程释放共享资源的时候,信号量加1,唤醒休眠的进程
3)二元信号量或双态信号量是最常见的信号量形式,可以被初始为任一正值
4)信号量集关联到一个semid_ds结构
5)创建信号量 semget(key_t, int nsems, int flag)
6) semctl 设置信号量
7) semop 设置信号量的值
8)信号量操作sembuf结构体
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag,
mode_t mode, unsigned int value);
#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
DESCRIPTION
sem_post() increments (unlocks) the semaphore pointed to by sem. If the semaphore's value
consequently becomes greater than zero, then another process or thread blocked in a
sem_wait(3) call will be woken up and proceed to lock the semaphore.
RETURN VALUE
sem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1
is returned, and errno is set to indicate the error.
八 共享存储
1)概念: 允许2个或更多进程共享一给定的存储区
2)每个共享存储关联到一个结构 struct shmid_ds,实际上这个结构体是共享内存的属性
3)创建共享存储 shmget(key_t,size_t,int)
4)设置共享存储 shmctl
5)绑定到当前进程的某个地址 ,方便使用 shmat
6)删除绑定 shmdt
7)删除标识符(键)shmctl + IPC_RMID
8)linux*享存储紧邻栈下面
9)共享内存的数据同步由信号量来实现
int shmget(key key,size_t size,int flag) 返回共享内存的标识iD(shmid)
int shmctl(int shmid,int cmd, struct shmid_ds * buf)
void* shmat(int shmid, const void * addr, int flag)
int shmdt(void * addr)