首页 > 代码库 > Linux 进程通信之 ——信号和信号量总结
Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存。
所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂。机制不同,复杂度也不一样。通信是一个广义上的意义,不仅仅指传递一些massege。他们的用法是基本相同的,所以仅仅要掌握了一种的用法,然后记住其他的用法就能够了。
1. 信号
在我学习的内容中,主要接触了信号来实现同步的机制,据说信号也能够用来做其他的事
情,可是我还不知道做什么。
信号和信号量是不同的,他们尽管都可用来实现同步和相互排斥,但前者是使用信号处理器来
进行的,后者是使用P,V*作来实现的。
使用信号要先知道有哪些信号,在Linux下有31个须要记住的通用信号,据说也是system
V中最经常使用的那些。这里略。
1. 1信号相关函数:
#include
int sigaction(int signo, const struct sigaction *act, struct sigaction
*oact);
该函数用来为进程安装信号处理器,struct sigaction数据是用来保存信号处理器的相
关信息。
#include
int sigemptyset(sigset_t *set);
将信号集合清空。
int sigfillset(sigset_t *set);
将信号集合设置成包括全部的信号。在对信号进行*作曾经一定要对信号集进行初始化。
int sigaddset(sigset_t *set, int signo);
向信号集中加入signo相应的新信号。
int sigdelset(sigset_t *set, int signo);
从信号集中删除signo相应的一个信号。
int sigismember(const sigset_t *set, int signo);
推断某个信号是否在信号集中。返回1则在,0则不在。
#include
int sigprocmask(int how,const sigset_t *set, sigset_t *oset);
用来设置进程的信号屏蔽码。信号屏蔽码能够用来在某段时间内堵塞一些信号集中的信
号,假设信号不在信号集中,就不必讨论它,由于肯定不响应,能否生成也不肯定,我
没有做过试验。
1.2我所理解的使用信号机制的方法:
使用信号,主要做的事情就是信号处理器的工作,这里面是你想做的事情。就像中断处理
函数一样。
在使用信号曾经,首先要初始化信号集,仅仅有在信号集里面的信号才会被考虑。
有两种方法能够初始化信号集,一种是设置空信号集,一种是将全部的信号都加到信号集
中。假设你自己想要的信号集不是这两种,能够在初始化了以后通过加入和删除信号进行
定制。
假设在进程运行的一段时间内不想对某些信号进行响应,则能够使用sigprocmask对当前
的信号集中的一些信号进行堵塞,稍后再运行。
当你将信号集设置完成后,在让他工作之前须要安装信号处理器。安装信号处理器能够实
现这几个功能:
指定信号处理函数的入口;指定信号屏蔽集合;指定信号处理器的一些标志。所谓信号处
理器,就是指定了一些处理方法,关键在于安装信号处理器,这是使正确的信号进行正确
的处理关键。在安装的时候,一定要对特定的信号赋予正确的信号处理函数。
我不知道不同进程之间的信号处理器能否混用,可是像一个特定的进程中有多少个信号处
理器这种问题是不能提的。由于信号处理器是一个概念,他针对的是信号,就是说假设
你指定了一个数据结构,用它来存储针对某个信号的处理信息,那么安装信号处理器就是
赋予这个数据结构一些相关信息,使用信号处理器就是用这个数据结构存储的信息来组织
一种机制当发生这个信号的时候会做一些你实现设置好的处理。可是假设区分不同进程中
对同一个信号的不同处理器?我想处理器可能仅仅对核它所属的进程有关的信号进行响应,
可是假设是这种话,那这是怎么实现的呢?
只是有一点是能够知道的,那就是每个信号都有一个信号处理器(确定的),能够动过
安装信号处理器来指定她的行为。信号处理器由他自己的信息存储区域(我不知道在什么
地方),可是能够通过向sigaction类型的数据结构向信号处理器的信息存储区域中传递
信息。这个数据结构由一个就能够了,由于它仅仅是暂时传递数据的载体。
可是sigpromask和信号处理器里面的sigmask是不一样的,前者是在进程当前流程设置信
号屏蔽,后者是指定在信号处理器作用时须要屏蔽掉的信号。比如,在设置某个特定信号
的信号处理器时,我们当然不能让它的信号处理器工作了,由于还没有设置完吗,这是我
们能够使用sigprocmask来让当前的流程開始堵塞该信号,当设置完信号处理器以后,再
用sigprocmask恢复被堵塞的信号。而以后再接收到该信号时,信号处理器就能够工作了。
我的想法是,同一个信号在不同的进程里能够有不同的信号处理器(一般应该有一个缺省
处理),当系统中发生一个信号时,全部能接受到的进程都能够接收到这个信号,并用他
们自己的信号处理器对这个信号做出各自的响应。
1.3怎样用信号来进行进程间的同步
同步的实现主要是通过在接受信号之前挂起进程,等待相关信号。所以涉及到异步信号安
全函数的概念。
只是信号怎样来实现进程间的相互排斥,我理解不是非常多,我想信号的主要用处还是在软中断
处理和进程同步。
2.信号量
信号量和信号是不同的东西,细致想想就能够理解:信号是实现约定的固定的值,而信号
量是一个变量记录着某些特定信息。
信号量这种东西我们在*作系统课程中就已经接触过了,这里仅仅是再草草说几句。信号量
分为有名和无名两种。进程间通信用有名信号量,同一进程内部通信一般用无名信号量。
这个我不再多说。
2.1信号量相关函数
#include
#include
#include
int semget(key_t key, int nsems, int semflg);
创建一个新的信号量组或获取一个已经存在的信号量组。
#include
#include
#include
int semop(int semid, struct sembuf *sop, int nsops);
semop函数能够一次对一个或多个信号量进行*作。
Int semctl(int sem_id, int semnum, int cmd,/*union semun arg*/…);
该函数能够用来获取一些信号量的使用信息或者是来对信号量进行控制。
2.2我对信号量机制的理解
对信号量的*作仅仅有两个:P, V。
为了在逻辑上便于组织信号量,信号量机制中有一个概念是信号量组。我们能够把一个信
号量组中创建相关的信号量,这样逻辑上清楚也便于管理。在使用之前你相同须要对他们
进行初始化:生成或打开信号量组,向当中生成或删除你指定的信号量。
对信号量的*作仅仅用两种,他都是通过semop函数中的sops參数来指定的,假设这个參数
是一个数组的话,那么就是对多个信号量进行*作。Sops參数中的sem_op字段指明了对信
号量进行的是P*作还是V*作。你仅仅要指定即可了,具体的*作不须要你去实现,函数中
都已经提供了。使用信号量,你得清楚信号量组id和信号量在信号量组中的位置(事实上也
就是另一个id)。一个信号量必须属于一个信号量组,否则不能被系统所使用。切记!
信号量和信号量组是不会被系统所自己主动清理的,所以当你的进程退出前,千万别忘了清理
你生成的那些信号量们。
信号量既能够实现相互排斥,也能够实现同步,这里就不说了,*作系统课程中是有介绍的。
3.消息队列
消息队列是比較高级的一种进程间通信方法,由于它真的能够在进程间传送massege,你
传送一个"I seek you"都能够。
一个消息队列能够被多个进程所共享(IPC就是在这个基础上进行的);假设一个进程的
消息太多一个消息队列放不下,也能够用多于一个的消息队列(只是可能管理会比較复
杂)。共享消息队列的进程所发送的消息中除了massege本身外另一个标志,这个标志
能够指明该消息将由哪个进程或者是哪类进程接受。每个共享消息队列的进程针对这个
队列也有自己的标志,能够用来声明自己的身份。
对于系统中的每个消息队列,都有一个数据结构来代表它,这个数据结构是msqid_ds,
这里略去不讲,在中能够看到它的原型。
3.1消息队列相关函数
使用消息队列之前,你要么获得这个消息队列,要么自己建立一个,否则是不能使用消息
队列的(我认为这都像是多余的话,请见谅)。当这个消息队列不再使用时,也一定要有
一个进程来删除消息队列,系统是不会自己主动的清理消息队列和msgid_ds的。
Int msgget(key_t key, int msgflg);
获取一个存在的消息队列的ID,或者是依据跟定的权限创建一个消息队列。可是怎么样去
删除这个消息队列,我还不十分清楚。
Int msgctl(int msqid, int cmd, struct msqid_ds *buf);
用来从msqid_ds中获取非常多消息队列本身的信息。
Int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg);
用于向队列发送消息。
Int msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, int
msgflg);
从队列中接收消息。
我这个文档里面对消息队列中的一些临界情况所述不多,由于这是我的小结,而非介绍。
在GNU C库技术中能够看到它的具体介绍。