UNIX下进程学习之管道和消息队列
linux多进程
僵尸进程是已经终止,但没有从进程表中清除的进程。
如果子进程先于父进程终止,而父经常没有调用wait接收子进程的信息,则子进程将转化为僵尸进程,直到父进程结束。
避免僵尸进程方法
1) wait 父进程主动调用wait(或收到信号后调用)接收子进程的死亡报告,释放子进程占用的系统进程表资源.
2) 托管法 父进程先于子进程死亡,则它的所有子进程转而由init进程领养
3) 忽略SIGC(H)LD信号 当父进程忽略此信号, 即使不执行wait,子进程结束时也不会产生僵尸进程。
4) 捕获SIGC(H)LD信号 父进程捕获SIGC(H)LD信号,并在捕获函数中等待wait子进程.
守护进程
守护进程是一个在后台长期运行的进程,独立于控制终端,周期性执行某项任务.
完成一个守护进程的编写至少包含以下几项
1)后台运行 托管法实现
2)独立控制终端 setsid()
3)清楚文件创建掩码 umask(0)
4)处理信号
查询IPC对象
ipcs
删除IPAC对象
ipcrm
IPC的三种对象在UNIX都存在限制,比如消息队列最大字节数.信号量最大信数.都可以更改内核参数来改变. www.zhishiwu.com
进程间通信
进程间通信有 管道 消息队列 信号量 共享内存
管道:
无名管道:int pipe(int fildes[2])
在UNIX中,创建无名管道的函数有pipe,popen,关闭无名管道的函数有pclose.
创建有名管mknod和mkfifo,创建有名管道函数mkfifo.
无名管道应用于父子进程,有名管道以文件的形式储存于磁盘等外部储存设备中,可在任意两个进程中应用.
消息队列
ipcs -a -q
目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。考虑到程序的可移植性,新开发的应用程序应尽量使用POSIX消息队列。
系统V消息队列是随内核持续的,只有在内核重起或者显式删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。 消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息
消息队列在UNIX内核中是一个先进先出的链表结构
UNIX用msgid_s结构管理消息队列 www.zhishiwu.com
消息队列的创建 int msgget(key_t key,int msgflag)
消息队列发送 int msgsnd(int msgid,void *msgp,int msgsz,int msgflg)
消息队列接收 int msgrcv(int msgid,void *msgp,int msgsz,long msgtype,int msgflg)
消息队列控制 int msgctl(int msgid,int cmd,struct msgid_ds *buf)
采用消息队列通信比采用管道通信具有更多的灵活性.通信的进程,不但没有血缘上的要求,也不需要进行同步处理.发送进程可以在任意时刻写入消息,也可以在接收消息之前结束执行.而使用管道,无论是无名管道还是有名管道,通信的两个进程都必选正在运行.
消息队列是IPC对象中的一种,与同样提供先进先出服务的管道相比,有如下特点
1)消息队列提供了消息数据的自动拆分功能,同时不能接收两次发的消息
2)消息队列提供了不完全随机读取的服务,引入消息类型后,一个队列在逻辑上可以化身为不同消息类型的链表,用户可以自行选择接收某条逻辑链表上的消息,而不必依次接收队列的首条消息.
3)消息队列提供了完全异步的读写服务,管道在使用时要求读写两端同时被打开,而消息队列没有这个限制,进程可以在任意时刻打开队列,也可以从队列中读取暂时不存在的消息.
创建消息队列的函数有msgget,发送消息队列的函数有msgsnd,从消息队列中接收消息的函数有msgrcv,控制消息队列的函数有msgctl,它可以查询消息队列数据结构,改变消息队列访问权限,改变消息队列属主信息和删除消息队列等功能.
作者 felixit0120