1,管道(无名管道)
1,打开和关闭管道
#include <unistd.h>
int pipe(int filedes[2]);
//filedes[0]用于读出数据,所以pipe会调用的O_RDONLY标志打开它,第二个文
件描述符filedes[1]用于写入数据,所以pipe用open调用的O_WRONLY标志打开它。
pipe执行成功返回0,出错返回-1,设置全局变量errno.
2,读写管道
用read从filedes[0]中读出数据,write向filedes[1]写入数据。
一般过程:一个进程调用pipe然后再调用fork产生一个子进程,因为子进程从父
进程继承了任何打开的文件描述符,就建立起了一个IPC通道,下一步取决于进程
是读数据还是写数据,一般的规则是读数据的进程关闭管道的写入端,而写数据的
进程关闭管道的读出端。而试图对一个管道的两端进行读写是一个严重的编程错
误,如果两个进程需要全双工的管道功能,父进程必须在fork之前打开两个管道。
3,简化了的函数
#include <stdio.h>
FILE *popen(const char *command, const char *mode);
int pclose(FILE *stream);
//popen创建一个管道然后fork出一个子进程,接着执行一个exec调用,调
用/bin/sh -c执行保存在command中的命令字符串,参数mode必须是r或w,在这里它
们和标准I/O库中定义一样,同样,如果mode为w,这个流被 附加到command的标准
输入,所以向这个流写入数据和向command的标准输入写入数据是一样的。如果
popen调用失败,则返回NULL,导致失败的出错条件被设置在出错变量errno中。
//关闭这个流时,使用pclose,它关闭I/O流,等待command来完成,并向调用的
进程返回它的退出状态,如果pclose调用失败,则返回-1.

2,FIFO(有名管道)
持久稳定:它们存在于文件系统中,能让无关联的进程交換数据,而且,它们能永
久地驻留在文件系统中。
》创建FIFO
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
//mkfifo用mode(八进制)指定的权限位创建一个名为pathname的FIFO。通常mode
中的值会被进程的umask修改。
mode_t mode = 0600;
  mode & ~umask.

》打开和关闭FIFO 
打开-open
关闭-close
删除-unlink
读取-read
写入-write
注意:1,FIFO的两端都必须在使用之前打开。2,如果FIFO是以O_NONBLOCK
和 O_RDONLY标志打开的,那么调用会立即返回,如果它是以O_NONBLOCK和
O_WRONLY打开的,在FIFO还没有为读出数据打开时,调用open会返回一个错误,并
把errno设置为ENXIO.如没有使用O_NONBLOCK它们将都被阻塞,如果没有数据。
和使用管道的情况类似,向一个没有为读出数据打开的FIFO写入数据会导致向写
入进程发送SIGPIPE信号,并且设置变量errno为EPIPE.在最后一个写数据的进程关
闭FIFO后,读数据的进程能在它的下一次读操作中检测到EOF标志。为保证多个进
程 向一个FIFO写数据时执行的是原子写操作,每个进程的写操作都必须写入少于
PIPE_BUF个字节的数据。

3,共享内存
共享内存是由内核出于在多个进程间交換信息的目的而留出的一块内存区
(段)。如果段的权限设置恰当,每个要访问该段内存的进程都可以把它映像到自
己私有的地址空间中。如果一个进程更新了段中的内容,那么其它进程立即会看到
更新(how?)。由一个进程创建的段也可以由另一个进程读写。内存共享这一名字表
达出是由多个进程分享对段及其保存的数据的访问权这一含义。
每个进程都把它自己对共享内存的映像放入到自己的地址空间。
》创建共享内存
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int flags);
//flags可以是一个或多个IPC_CREAT, IPC_EXCL和一组权限位(模式)按
位“或”的結果,权限位以八进制表示。IPC_EXCL确保如果段已经存在,调用执行失
败,而不是返回一个已经存在的段的标识符。
//key既可以是IPC_PRIVATE也可以是fork函数返回的一个关键字。size指定段的
大小,但它以PAGE_SIZE的值为界。
》附加共享内存区
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid, char *shmadr, int flags);
int shmdt(char *shmadr);  //共享内存区的分离。
//shmid是你要附加到的共享内存区的标识符,在函数shmat 中,如果shmadr为
0,则内核会把段映像到调用进程的地址空间中它所选定的位置。如果shmadr不为
0,因为内核把段映像到它所指定的地址,显然这样很难巧合。所以总是把shmadr
设置为0。flags可以为SHM_RDONLY,意味被附加的段是只读的,否则是可读写的。
//shmdt附加在shmaddr的段从调用进程的地址空间中分离出去,这个地址必须是
调用shmget返回的。

4,消息队列 
消息队列是一个消息的链接列表,消息都保存在内核中,进程通过一个和共享区
使用的标识符同种类的标识符标识消息。
》创建和打开消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int flags);
//如果调用成功,它相对应包含在key中值,返回新的或已有队列的队列ID。
如果key为IPC_PRIVATE,则在底层实现生成的一个关键字的值创建一个新队列。如
果 没有超出系统对队列数量和所有队列中总字节数的限制,则使用IPC_PRIVATE
保证了创建一个新的队列。
类似的,如果key不是IPC_PRIVATE,key也和一个已有队列的key不相同,而且在
参数flags中设置了IPC_CREAT位,那么就创建一个新队列,否则--也就是说,如
果key不是IPC_PRIVATE而且参数flags中没有设置IPC_CREAT位--msgget返回和
key关联的已有队列的队列ID.
》向队列中写入消息
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flags);
》删除消息队列 
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf);
// cmd:
IPC_RMID --删除队列 msqid
IPC_STAT--用队列的msqid_ds结构填充buf,并让你查看队列的内容而不会删除
任何消息。因为这是一种非破坏性读操作,你可以认为它和msgrcv类似。
IPC_SET--让你改变队列的UID,GID,访问模式和队列的最大字节数。

5,信号灯
创建信号灯
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int flags);
//semget返回和nsems信号灯集合相关的信号灯标识符,key为IPC_PRIVATE,或者
如果key还没有使用并且在flags中设置了IPC_CREAT位,则创建新的信号灯集合。
和共享内存区和消息队列类似,flags也能和权限位(八进制形式)按位进
行“或”操作来为信号灯设置访问模式。但要注意,信号灯有读取和改变的权限,而
不是读取和写入的权限。因为你只会通过增加或减小信号灯的值来改变(或调整)
它的状态。


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *semops, unsigned nops);
semid 是先前的semget返回的信号灯标识符,它指向要操作的信号灯集合。nops
是semops指向的sembuf结构数组的元素个数。
struct sembuf{
short sem_num; /* Semaphore number */
short sem_op; /* The operation to perform */
short sem_flg; /* Flags controlling the operation*/
//sem_num是信号灯的编号,其值从0到nsems-1,sem_op是执行的操作,而
sem_flg调整semop的行为。sem_op能够为正值,负值,和0。
如果sem_op 为正,信号灯控制的资源被释放,而且信号灯的值增加。
如果sem_op 为负,调用进程表示它将等待直到受控资源被释放,此时信号灯的
值减小而资源被调用进程加锁。
如果sem_op为0,调用进程阻塞直到信号灯变为0;如果信号灯已经是0,调用
立即返回。sem_flg可以为IPC_NOWAIT,或者为 SEM_UNDO--当调用semop的进程退
出后执行的操作将被撤销。

》控制和删除信号灯
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, union semun arg);