`
yzd
  • 浏览: 1817481 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

linuxIPC——信号(上)

 
阅读更多
<p><span style="font-size: medium;"><a name="1"><span class="atitle">一、信号及信号来源</span>
</a>
</span>
</p>
<p>
        <span style="font-size: medium;"><strong>信号本质</strong>
</span>
      </p>
<p><span style="font-size: medium;">信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。</span>
</p>
<p><span style="font-size: medium;">信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。</span>
</p>
<p>
        <span style="font-size: medium;"><strong>信号来源</strong>
</span>
      </p>
<p><span style="font-size: medium;">信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源,最常用发送信号的系统函数是kill, raise, alarm和setitimer以及sigqueue函数,软件来源还包括一些非法运算等操作。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="2"><span class="atitle">二、信号的种类</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">可以从两个不同的分类角度对信号进行分类:(1)可靠性方面:可靠信号与不可靠信号;(2)与时间的关系上:实时信号与非实时信号。在《Linux环境进程间通信(一):管道及有名管道》的附1中列出了系统所支持的所有信号。</span>
</p>
<p><span style="font-size: medium;"><a name="N10060"><span class="smalltitle">1、可靠信号与不可靠信号</span>
</a>
</span>
</p>
<p>
        <span style="font-size: medium;"><strong>"不可靠信号"</strong>
</span>
      </p>
<p><span style="font-size: medium;">Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,
因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(Red hat
7.2中,SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:</span>
</p>
<ul>
<li>
<span style="font-size: medium;">进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。</span>
</li>
<li>
<span style="font-size: medium;">信号可能丢失,后面将对此详细阐述。
          <br>
因此,早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。
        </span>
</li>
</ul>
<p><span style="font-size: medium;">Linux支持不可靠信号,但是对不可靠信号机制做了改进:在调用完信号处理函数后,不必重新调用该信号的安装函数(信号安装函数是在可靠机制上的实现)。因此,Linux下的不可靠信号问题主要指的是信号可能丢失。</span>
</p>
<p>
        <span style="font-size: medium;"><strong>"可靠信号"</strong>
</span>
      </p>
<p><span style="font-size: medium;">随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。所以,后来出现的各种Unix版本分别在这方面进行了研究,力图实
现"可靠信号"。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不
会丢失。同时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction()。POSIX.4对可靠信号机制
做了标准化。但是,POSIX只对可靠信号机制应具有的功能以及信号机制的对外接口做了标准化,对信号机制的实现没有作具体的规定。</span>
</p>
<p><span style="font-size: medium;">信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。Linux在支持新版本的
信号安装函数sigation()以及信号发送函数sigqueue()的同时,仍然支持早期的signal()信号安装函数,支持信号发送函数
kill()。</span>
</p>
<p><span style="font-size: medium;">注:不要有这样的误解:由sigqueue()发送、sigaction安装的信号就是可靠的。事实上,可靠信号是指后来添加的新信号
(信号值位于SIGRTMIN及SIGRTMAX之间);不可靠信号是信号值小于SIGRTMIN的信号。信号的可靠与不可靠只与信号值有关,与信号的发
送及安装函数无关。目前linux中的signal()是通过sigation()函数实现的,因此,即使通过signal()安装的信号,在信号处理函
数的结尾也不必再调用一次信号安装函数。同时,由signal()安装的实时信号支持排队,同样不会丢失。</span>
</p>
<p><span style="font-size: medium;">对于目前linux的两个信号安装函数:signal()及sigaction()来说,它们都不能把SIGRTMIN以前的信号变成
可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过
sigaction安装的信号都能传递信息给信号处理函数(对所有信号这一点都成立),而经过signal安装的信号却不能向信号处理函数传递信息。对于
信号发送函数来说也是一样的。</span>
</p>
<p><span style="font-size: medium;"><a name="N1008F"><span class="smalltitle">2、实时信号与非实时信号</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">早期Unix系统只定义了32种信号,Ret
hat7.2支持64种信号,编号0-63(SIGRTMIN=31,SIGRTMAX=63),将来可能进一步增加,这需要得到内核的支持。前32种信
号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的缺省动作。如按键盘的CTRL
^C时,会产生SIGINT信号,对该信号的默认反应就是进程终止。后32个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都
被接收。实时信号是POSIX标准的一部分,可用于应用进程。</span>
</p>
<p><span style="font-size: medium;">非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="3"><span class="atitle">三、进程对信号的响应</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">进程可以通过三种方式来响应一个信号:(1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及
SIGSTOP;(2)捕捉信号。定义信号处理函数,当信号发生时,执行相应的处理函数;(3)执行缺省操作,Linux对每种信号都规定了默认操作,详
细情况请参考[2]以及其它资料。注意,进程对实时信号的缺省反应是进程终止。</span>
</p>
<p><span style="font-size: medium;">Linux究竟采用上述三种方式的哪一个来响应信号,取决于传递给相应API函数的参数。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="4"><span class="atitle">四、信号的发送</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">发送信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。</span>
</p>
<p><span style="font-size: medium;">1、kill()
        <br>
#include &lt;sys/types.h&gt;
        <br>
#include &lt;signal.h&gt;
        <br>
int kill(pid_t pid,int signo)
        <br></span>
      </p>
<table class="ibm-data-table" style="width: 60%;" border="1"><tbody>
<tr>
<td>
<span style="font-size: medium;">参数pid的值</span>
</td>
<td>
<span style="font-size: medium;">信号的接收进程</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">pid&gt;0</span>
</td>
<td>
<span style="font-size: medium;">进程ID为pid的进程</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">pid=0</span>
</td>
<td>
<span style="font-size: medium;">同一个进程组的进程</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">pid&lt;0 pid!=-1</span>
</td>
<td>
<span style="font-size: medium;">进程组ID为 -pid的所有进程</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">pid=-1</span>
</td>
<td>
<span style="font-size: medium;">除发送进程自身外,所有进程ID大于1的进程</span>
</td>
</tr>
</tbody></table>
<p><span style="font-size: medium;">Sinno是信号值,当为0时(即空信号),实际不发送任何信号,但照常进行错误检查,因此,可用于检查目标进程是否存在,以及当前进
程是否具有向目标发送信号的权限(root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程
发送信号)。</span>
</p>
<p><span style="font-size: medium;">Kill()最常用于pid&gt;0时的信号发送,调用成功返回 0;  否则,返回 -1。
注:对于pid&lt;0时的情况,对于哪些进程将接受信号,各种版本说法不一,其实很简单,参阅内核源码kernal/signal.c即可,上表中的规则是参考red hat 7.2。</span>
</p>
<p><span style="font-size: medium;">2、raise()
        <br>
#include &lt;signal.h&gt;
        <br>
int raise(int signo)
        <br>
向进程本身发送信号,参数为即将发送的信号值。调用成功返回 0;否则,返回 -1。
      </span>
</p>
<p><span style="font-size: medium;">3、sigqueue()
        <br>
#include &lt;sys/types.h&gt;
        <br>
#include &lt;signal.h&gt;
        <br>
int sigqueue(pid_t pid, int sig, const union sigval val)
        <br>
调用成功返回 0;否则,返回 -1。
      </span>
</p>
<p><span style="font-size: medium;">sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用。</span>
</p>
<p><span style="font-size: medium;">sigqueue的第一个参数是指定接收信号的进程ID,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> typedef union sigval {
int  sival_int;
void *sival_ptr;
}sigval_t;
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程
组。如果signo=0,将会执行错误检查,但实际上不发送任何信号,0值信号可用于检查pid的有效性以及当前进程是否有权限向目标进程发送信号。</span>
</p>
<p><span style="font-size: medium;">在调用sigqueue时,sigval_t指定的信息会拷贝到3参数信号处理函数(3参数信号处理函数指的是信号处理函数由
sigaction安装,并设定了sa_sigaction指针,稍后将阐述)的siginfo_t结构中,这样信号处理函数就可以处理这些信息了。由于
sigqueue系统调用支持发送带参数信号,所以比kill()系统调用的功能要灵活和强大得多。</span>
</p>
<p><span style="font-size: medium;">注:sigqueue()发送非实时信号时,第三个参数包含的信息仍然能够传递给信号处理函数;
sigqueue()发送非实时信号时,仍然不支持排队,即在信号处理函数执行过程中到来的所有相同信号,都被合并为一个信号。</span>
</p>
<p><span style="font-size: medium;">4、alarm()
        <br>
#include &lt;unistd.h&gt;
        <br>
unsigned int alarm(unsigned int seconds)
        <br>
专门为SIGALRM信号而设,在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间。进程调用alarm后,任何以前的alarm()调用都将无效。如果参数seconds为零,那么进程内将不再包含任何闹钟时间。
        <br>
返回值,如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
      </span>
</p>
<p><span style="font-size: medium;">5、setitimer()
        <br>
#include &lt;sys/time.h&gt;
        <br>
int setitimer(int which, const  struct  itimerval  *value, struct itimerval *ovalue));
        <br>
setitimer()比alarm功能强大,支持3种类型的定时器:
      </span>
</p>
<ul>
<li>
<span style="font-size: medium;">ITIMER_REAL: 设定绝对时间;经过指定的时间后,内核将发送SIGALRM信号给本进程;</span>
</li>
<li>
<span style="font-size: medium;">ITIMER_VIRTUAL   设定程序执行时间;经过指定的时间后,内核将发送SIGVTALRM信号给本进程;</span>
</li>
<li>
<span style="font-size: medium;">ITIMER_PROF      设定进程执行以及内核因本进程而消耗的时间和,经过指定的时间后,内核将发送ITIMER_VIRTUAL信号给本进程;</span>
</li>
</ul>
<p><span style="font-size: medium;">Setitimer()第一个参数which指定定时器类型(上面三种之一);第二个参数是结构itimerval的一个实例,结构itimerval形式见附录1。第三个参数可不做处理。</span>
</p>
<p><span style="font-size: medium;">Setitimer()调用成功返回0,否则返回-1。</span>
</p>
<p><span style="font-size: medium;">6、abort()
        <br>
#include &lt;stdlib.h&gt;
        <br>
void abort(void);
      </span>
</p>
<p><span style="font-size: medium;">向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。该函数无返回值。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="5"><span class="atitle">五、信号的安装(设置信号关联动作)</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">如果进程要处理某一信号,那么就要在进程中安装该信号。安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号;该信号被传递给进程时,将执行何种操作。</span>
</p>
<p><span style="font-size: medium;">linux主要有两个函数实现信号的安装:signal()、sigaction()。其中signal()在可靠信号系统调用的基础
上实现,
是库函数。它只有两个参数,不支持信号传递信息,主要是用于前32种非实时信号的安装;而sigaction()是较新的函数(由两个系统调用实
现:sys_signal以及sys_rt_sigaction),有三个参数,支持信号传递信息,主要用来与 sigqueue()
系统调用配合使用,当然,sigaction()同样支持非实时信号的安装。sigaction()优于signal()主要体现在支持信号带有参数。</span>
</p>
<p><span style="font-size: medium;">1、signal()
        <br>
#include &lt;signal.h&gt;
        <br>
void (*signal(int signum, void (*handler))(int)))(int);
        <br>
如果该函数原型不容易理解的话,可以参考下面的分解方式来理解:
        <br>
typedef void (*sighandler_t)(int);
        <br>
sighandler_t signal(int signum, sighandler_t handler));
        <br>
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。
        <br>
如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
      </span>
</p>
<p><span style="font-size: medium;">2、sigaction()
        <br>
#include &lt;signal.h&gt;
        <br>
int sigaction(int signum,const  struct  sigaction  *act,struct sigaction *oldact));
      </span>
</p>
<p><span style="font-size: medium;">sigaction函数用于改变进程接收到特定信号后的行为。该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP
外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。第二个参数是指向结构sigaction的一个实例的指针,在结构
sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;第三个参数oldact指向的对象用来保存原来对相应信号
的处理,可指定oldact为NULL。如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。</span>
</p>
<p><span style="font-size: medium;">第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等。</span>
</p>
<p><span style="font-size: medium;">sigaction结构定义如下:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> struct sigaction {
          union{
            __sighandler_t _sa_handler;
            void (*_sa_sigaction)(int,struct siginfo *, void *);
            }_u
                     sigset_t sa_mask;
                    unsigned long sa_flags;
                  void (*sa_restorer)(void);
                  }
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">其中,sa_restorer,已过时,POSIX不支持它,不应再被使用。</span>
</p>
<p><span style="font-size: medium;">1、联合数据结构中的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数,即用户指定的信号处理函数。除了可以是用户自定义的处理函数外,还可以为SIG_DFL(采用缺省的处理方式),也可以为SIG_IGN(忽略信号)。</span>
</p>
<p><span style="font-size: medium;">2、由_sa_handler指定的处理函数只有一个参数,即信号值,所以信号不能传递除信号值之外的任何信息;由
_sa_sigaction是指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参
数为信号值,第三个参数没有使用(posix没有规范使用该参数的标准),第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值,
参数所指向的结构如下:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> siginfo_t {
                  int      si_signo;  /* 信号值,对所有信号有意义*/
                  int      si_errno;  /* errno值,对所有信号有意义*/
                  int      si_code;   /* 信号产生的原因,对所有信号有意义*/
        union{          /* 联合数据结构,不同成员适应不同信号 */ 
          //确保分配足够大的存储空间
          int _pad[SI_PAD_SIZE];
          //对SIGKILL有意义的结构
          struct{
              ...
              }...
            ... ...
            ... ...         
          //对SIGILL, SIGFPE, SIGSEGV, SIGBUS有意义的结构
              struct{
              ...
              }...
            ... ...
            }
      }
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">注:为了更便于阅读,在说明问题时常把该结构表示为附录2所表示的形式。</span>
</p>
<p><span style="font-size: medium;">siginfo_t结构中的联合数据成员确保该结构适应所有的信号,比如对于实时信号来说,则实际采用下面的结构形式:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> typedef struct {
int si_signo;
int si_errno;
int si_code;
union sigval si_value;
} siginfo_t;
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">结构的第四个域同样为一个联合数据结构:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> union sigval {
int sival_int;
void *sival_ptr;
}
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">采用联合数据结构,说明siginfo_t结构中的si_value要么持有一个4字节的整数值,要么持有一个指针,这就构成了与信号
相关的数据。在信号的处理函数中,包含这样的信号相关数据指针,但没有规定具体如何对这些数据进行操作,操作方法应该由程序开发人员根据具体任务事先约
定。</span>
</p>
<p><span style="font-size: medium;">前面在讨论系统调用sigqueue发送信号时,sigqueue的第三个参数就是sigval联合数据结构,当调用sigqueue
时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。这样,在发送信号同时,就可以让信号传递一些附加信息。信号可以传递信息对程序开发是非常
有意义的。</span>
</p>
<p><span style="font-size: medium;">信号参数的传递过程可图示如下:</span>
</p>
<p>
     
        <span style="font-size: medium;"><br><img src="http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/2.gif" border="0" alt="" width="580" height="176"></span>
       
      <span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">3、sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位。</span>
</p>
<p><span style="font-size: medium;">注:请注意sa_mask指定的信号阻塞的前提条件,是在由sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。</span>
</p>
<p><span style="font-size: medium;">4、sa_flags中包含了许多标志位,包括刚刚提到的SA_NODEFER及SA_NOMASK标志位。另一个比较重要的标志位是
SA_SIGINFO,当设定了该标志位时,表示信号附带的参数可以被传递到信号处理函数中,因此,应该为sigaction结构中的
sa_sigaction指定处理函数,而不应该为sa_handler指定信号处理函数,否则,设置该标志变得毫无意义。即使为
sa_sigaction指定了信号处理函数,如果不设置SA_SIGINFO,信号处理函数同样不能得到信号传递过来的数据,在信号处理函数中对这些信
息的访问都将导致段错误(Segmentation fault)。</span>
</p>
<p><span style="font-size: medium;">注:很多文献在阐述该标志位时都认为,如果设置了该标志位,就必须定义三参数信号处理函数。实际不是这样的,验证方法很简单:自己实现
一个单一参数信号处理函数,并在程序中设置该标志位,可以察看程序的运行结果。实际上,可以把该标志位看成信号是否传递参数的开关,如果设置该位,则传递
参数;否则,不传递参数。</span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="6"><span class="atitle">六、信号集及信号集操作函数:</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">信号集被定义为一种数据类型:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">信号集用来描述信号的集合,linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。下面是为信号集操作定义的相关函数:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;"> #include &lt;signal.h&gt;
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
sigemptyset(sigset_t *set)初始化由set指定的信号集,信号集里面的所有信号被清空;
sigfillset(sigset_t *set)调用该函数后,set指向的信号集中将包含linux支持的64种信号;
sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号;
sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号;
sigismember(const sigset_t *set, int signum)判定信号signum是否在set指向的信号集中。
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<div class="ibm-alternate-rule">
<hr>
</div>
<p><span style="font-size: medium;"><a name="7"><span class="atitle">七、信号阻塞与信号未决:</span>
</a>
</span>
</p>
<p><span style="font-size: medium;">每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。下面是与信号阻塞相关的几个函数:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">#include &lt;signal.h&gt;
int  sigprocmask(int  how,  const  sigset_t *set, sigset_t *oldset));
int sigpending(sigset_t *set));
int sigsuspend(const sigset_t *mask));
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">sigprocmask()函数能够根据参数how来实现对信号集的操作,操作主要有三种:</span>
</p>
<table class="ibm-data-table" style="width: 70%;" border="0"><tbody>
<tr>
<td>
<span style="font-size: medium;">参数how</span>
</td>
<td>
<span style="font-size: medium;">进程当前信号集</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">SIG_BLOCK</span>
</td>
<td>
<span style="font-size: medium;">在进程当前阻塞信号集中添加set指向信号集中的信号</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">SIG_UNBLOCK</span>
</td>
<td>
<span style="font-size: medium;">如果进程阻塞信号集中包含set指向信号集中的信号,则解除对该信号的阻塞</span>
</td>
</tr>
<tr>
<td>
<span style="font-size: medium;">SIG_SETMASK</span>
</td>
<td>
<span style="font-size: medium;">更新进程阻塞信号集为set指向的信号集</span>
</td>
</tr>
</tbody></table>
<p><span style="font-size: medium;">sigpending(sigset_t *set))获得当前已递送到进程,却被阻塞的所有信号,在set指向的信号集中返回结果。</span>
</p>
<p><span style="font-size: medium;">sigsuspend(const sigset_t *mask))用于在接收到某个信号之前,
临时用mask替换进程的信号掩码, 并暂停进程执行,直到收到信号为止。sigsuspend
返回后将恢复调用之前的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR。</span>
</p>
<p><span style="font-size: medium;">附录1:结构itimerval:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">            struct itimerval {
                struct timeval it_interval; /* next value */
                struct timeval it_value;    /* current value */
            };
            struct timeval {
                long tv_sec;                /* seconds */
                long tv_usec;               /* microseconds */
            };
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">附录2:三参数信号处理函数中第二个参数的说明性描述:</span>
</p>
<table style="width: 100%;" border="0" cellspacing="0" cellpadding="0"><tbody><tr>
<td class="code-outline">
<pre class="displaycode"><span style="font-size: medium;">siginfo_t {
int      si_signo;  /* 信号值,对所有信号有意义*/
int      si_errno;  /* errno值,对所有信号有意义*/
int      si_code;   /* 信号产生的原因,对所有信号有意义*/
pid_t    si_pid;    /* 发送信号的进程ID,对kill(2),实时信号以及SIGCHLD有意义 */
uid_t    si_uid;    /* 发送信号进程的真实用户ID,对kill(2),实时信号以及SIGCHLD有意义 */
int      si_status; /* 退出状态,对SIGCHLD有意义*/
clock_t  si_utime;  /* 用户消耗的时间,对SIGCHLD有意义 */
clock_t  si_stime;  /* 内核消耗的时间,对SIGCHLD有意义 */
sigval_t si_value;  /* 信号值,对所有实时有意义,是一个联合数据结构,
                          /*可以为一个整数(由si_int标示,也可以为一个指针,由si_ptr标示)*/

void *   si_addr;   /* 触发fault的内存地址,对SIGILL,SIGFPE,SIGSEGV,SIGBUS 信号有意义*/
int      si_band;   /* 对SIGPOLL信号有意义 */
int      si_fd;     /* 对SIGPOLL信号有意义 */
}
</span>
</pre>
</td>
</tr></tbody></table>
<p><span style="font-size: medium;"><br></span>
</p>
<p><span style="font-size: medium;">实际上,除了前三个元素外,其他元素组织在一个联合结构中,在联合数据结构中,又根据不同的信号组织成不同的结构。注释中提到的对某种信号有意义指的是,在该信号的处理函数中可以访问这些域来获得与信号相关的有意义的信息,只不过特定信号只对特定信息感兴趣而已。</span>
</p>
分享到:
评论

相关推荐

    Linux学习笔记Linux学习资料Linux教程

    【linux学习笔记--18】POSIX IPC——信号量.doc 【linux学习笔记--19】POSIX IPC——共享内存.doc 【linux学习笔记-10】Linux进程相关系统调用(三).doc 【linux学习笔记-11】守护进程daemon.doc 【linux学习笔记-...

    非常宝贵的LINUX学习笔记

    【linux学习笔记-1】使用GDB调试简单的用户程序 【linux学习笔记-2】父子进程共享文件描述符 【linux学习笔记-3】文件操作...【linux学习笔记--18】POSIX IPC——信号量 【linux学习笔记--19】POSIX IPC——共享内存

    linux源代码分析——消息管理

    在操作系统中,有些进程存在着相互制约的关系,这些制约关系来源于并行进程的相互合作和资源共享。...在linux 中支持UNIX SYSTEM V 的三种通信机制: 消息队列, 信号量和共享内存. 现就消息队列这种机制进行分析.

    linux系统进程间通信——共享内存(System V版本)

    之前用过Prosix版本的共享内存和信号量,一直没有实践System V版本的,主要是因为其信号量集的概念操作有些复杂,今天试着写一个SV版本的共享内存进程间通信,使用信号量同步。程序提供了几个简单的用于操作SV版本...

    Unix环境高级编程(APUE)——linux入门必学

    书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在此基础上介绍了多个应用...

    Linux高性能服务器编程

    《Linux高性能服务器编程》共17章,分为3个部分:第一部分对Linux服务器编程的核心基础——TCP/IP协议进行了深入的解读和阐述,包括TCP/IP协议族、TCP/IP协议,以及一个经典的TCP/IP通信案例;第二部分对高性能...

    Linux程序设计 第4版.haozip01

    14.1.3 linux的信号量机制 490 14.1.4 使用信号量 492 14.2 共享内存 496 14.2.1 shmget函数 497 14.2.2 shmat函数 497 14.2.3 shmdt 498 14.2.4 shmctl 498 14.3 消息队列 502 14.3.1 msgget函数 502 ...

    Linux程序设计 第4版.haozip02

    14.1.3 linux的信号量机制 490 14.1.4 使用信号量 492 14.2 共享内存 496 14.2.1 shmget函数 497 14.2.2 shmat函数 497 14.2.3 shmdt 498 14.2.4 shmctl 498 14.3 消息队列 502 14.3.1 msgget函数 502 ...

    Linux内核工作原理 word版本 强烈推荐

    信号与管道是 其中的两种,Linux同时还支持系统V IPC机制。这些进程间通讯机制在IPC一章中描叙。 外部设备互连(PCI)标准已经成为PC上低价位高数传率的总线标准。PCI一章将描叙Linux核心是如何初始化并使用PCI总线...

    Android驱动开发权威指南

    第二篇 勿于浮砂筑高台——Linux驱动基础篇 第3章Linux内核综述 3.1 OS基本概念 3.1.1多用户系统 3.1.2用户和组 3.1.3进程 3.1.4 Linux单核架构 3.2 Linux内核综述 3.2.1进程/内核模型综述 3.2.2内存管理综述 3.2.3...

    Linux网络编程

    4.8.3 信号量的实例——semtool,交互式的信号量使用工具.......103 4.9 共享内存(Shared Memory) ............109 4.9.1 有关的数据结构.....109 4.9.2 有关的函数......... 110 4.9.3 共享内存应用举例——shmtool...

    linux 网络编程源代码

    1.5 Linux 的发展.................................................................................................. 11 1.5.1 Linux 的发展历史 ..............................................................

    Linux网络编程.pdf socket tcp udp

    1.5 Linux 的发展.................................................................................................. 11 1.5.1 Linux 的发展历史 ............................................................

Global site tag (gtag.js) - Google Analytics