进程间通信和同步
进程间通信和同步
半双工管道
原型:int pipe(int filedes[2]);
实质上是创建两个文件描述符,filedes[0]用于读,filedes[1]用于写。
当写入数据的数目小于PIPE_BUF时,写入是原子的,当大于PIPE_BUF时,可能不是原子的。
如果管道是空的,那么read会被阻塞,如果管道是满的,那么write会被阻塞。
命名管道
原型:int mkfifo(const char *pathname,mode_t mode); //可用shell命令mkfifo创建
FIFO中,必须使用一个open函数来显式建立联接到管道的通道。一般来说FIFO总是处于阻塞的状态,如果FIFO打开时设置了读权限,则读进程将一直阻塞到其他进程打开该FIIFO并且向管道中写入数据,如果一个进程打开一个管道写入数据,当没有进程从管道读取数据时,写管道操作也是阻塞的。如果不希望进行命名管道操作的时候发生阻塞,可以调用open()调用中的O_NOBLOCK标志,以关闭默认的阻塞动作
消息队列
消息缓冲区结构msgbuf
struct msgbuf{
long mtype;
char mtext[1];
}
mtext可变长,缓冲区最大为#define MSGMAX 8192包括mtype 4字节。
内部的结构:
struct msqid_ds{
struct ipc_perm msg_perm;
time_t msg_stime; //发送到队列的最后一个消息的时间戳
time_t msg_rtime; //从队列中获取的最后一个消息的时间戳
time_t msg_ctime; //对队列进行最后一次变动的时间戳
unsigned long __msg_cbytes; //在队列上所驻留的字节总数
msgqnum_t msg_qnum; //当前处于队列中的消息数目
msglen_t msg_qbytes; //队列中能容忍的字节的最大数目
pid_t msg_lspid; //发送最后一个消息进程的PID
pid_t msg_lrpif; //接受最后一个消息进程的PID
};
struct ipc_perm{
key_t key; //函数msgget()使用的键值
uid_t uid; //用户的UID
gid_t gid; //用户的GID
uid_t cuid; //建立者的UID
git_t cgid; //建立者的GID
unsigned short mode; //权限
unsigned short seq; //序列号
};
键值构造函数ftok():
原型:key_t ftok(const char *pathname,int proj_id);
pathname必须是已存在的目录,proj_id则是一个8位的值,通常用a,b等表示。
获得消息msgget()函数:
原型:int msgget(key_t key,int msgflg);
第一个参数是键值,可以用ftok()函数生成,msgflag可指定权限,也可以指定操作IPC_CREATE,IPC_EXCL。IPC_EXCL本身没什么作用,但和IPC_CREATE一起用时可在已存在消息队列时返回一个错误。
成功返回标识符,错误返回-1
发送消息函数msgsnd()
原型:int msgsnd(int msqid,conset void *msgp,size_t msgsz,int msgflg);
msgfls可以为0也可以为IPC_NOWAIT,如果消息队列已满,则消息不会写入。如果没有指定IPC_NOWAIT,那么会阻塞。
接受消息msgrcv()
原型:ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);
msgtype指定获取消息的类型如果传0,则获取最老的消息,忽略类型。msgsz表示消息缓冲区结构的大小,不包括mtype的长度。
如果msgflg为IPC_NOWAIT,则在没有消息时返回ENOMSG,否则阻塞。
消息控制msgctl()函数
原型:int msgctl(int msqid,int cmd,struct msgqid_ds *buf);
cmd如下
IPC_STAT | 获得队列的msqid_ds结构,并把他存放到buf变量所指的地址中 |
IPC_SET | 设置队列的msqid_ds结构的ipc_perm成员值,它从buf中取得该值 |
IPC_RMD | 从内核删除该队列 |
信号量:
信号量数据结构:
union semun{
int val; //整形变量
struct semid_ds *buf; //semid_ds结构指针
unsigned short *array; //数组类型
struct seminfo *__buf; //信号量内部结构
};
新建信号量函数semget()
原型:int semget(key_t,int nsems,int semflg);
用于创建一个新的信号量集合,或者访问现有的集合。key是ftok产生的键值,nsems可以指定新的集合中应该创建的信号量的数目。第三个参数semflg是打开信号量的方式。
semflg指定权限,也可以加上IPC_CREATE、IPC_EXCL
信号量操作函数semop()
原型:int semop(int semid,struct sembuf *sops,unsigned nsops);
第二个参数是个指针,指向将要在信号量集合上执行操作的一个数组,而第三个参数则是该数组中操作的个数。
struct sembuf{
ushort sem_num; //信号量的编号
short sem_op; //信号量的操作
short sem_flg; //信号量的操作标志
}
sem_op如果为正,则从信号量加上一个值,为负减一个,为0将进程设置为睡眠状态, 直到信号量的值为0为止。
控制信号量参数semctl()
原型:int semctl(int semid,int semnum,int cmd,...);
semid是调用semget返回的值。semnum是要执行操作的信号量的编号,对于第一个信号量,他的索引值是0。cmd参数代表将要在该集合执行的命令
cmd取值:
IPC_STAT | 获取某个集合的semid_ds结构,将它存储到semun联合体的buf参数指定的地址中 |
IPC_SET | 设置某个集合的semid_ds结构的ipc_perm成员的值,该命令所取得值从semun联合体的buf参数中取到 |
IPC_RMID | 从内核中删除该集合 |
GETALL | 获取集合值中所有信号量的值,整数值存放在无符号短整数的一个数组中该数组由联合体的array成员所指定 |
GETNCNT | 返回当前正在等待资源的进程的数目 |
GETPID | 返回最后一次执行semop调用的进程的PID |
GETVAL | 返回集合中某个信号量的值 |
GETZCNT | 返回正在等待资源利用率达百分之百的进程的数目 |
SETALL | 设置集合中所有信号量的值为联合体array成员所包含的对应值 |
SETVAL | 把集合中单个信号量的值设置为联合体的val成员的值 |
共享内存:
创建共享内存函数shmget()
原型:int shmget(key_t key,size_t size,int shmflg);
获得共享内存地址函数shmat()
原型:void * shmat(int shmid,const void *shmaddr,int shmflg);
shmaddr若为0,则内核试着查找一个为映射的区域。
SHM_RND可以与标志参数进行OR操作,可以让传送的地址页对齐
SHM_RDONLY,标志共享内存段为只读。
删除共享内存shmdt()
原型:int shmdt(const void *shmaddr);
切断进程与该内存段的联系,非真正删除。
控制函数shmctl()
原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);
与msgctl完全类似。
信号:
信号截取函数signal()
原型:sighandler_t signal(int signum,sighandler_t handler);
handler函数原型:void sighandler(int signo); signo将传入信号值
向进程发送信号kill()和raise()
原型:int kill(pid_t pid,int sig);
int raise(int sig);
kill函数当pid为0时群发所有进程。raise是在当前进程自举一个信号。
本文出自http://qianyang.blog.51cto.com/,转载请务必注明出处
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。