linux环境进程间通信(二) 信号(下).htm

来自「关于Linux内核进程间通信的几篇文章」· HTM 代码 · 共 848 行 · 第 1/4 页

HTM
848
字号
                  <TR>
                    <TD class=code-outline><PRE class=displaycode>#include &lt;signal.h&gt;
int sigwaitinfo(sigset_t *set, siginfo_t *info).
</PRE></TD></TR></TBODY></TABLE><BR>该函数与sigsuspend()类似,阻塞一个进程直到特定信号发生,但信号到来时不执行信号处理函数,而是返回信号值。因此为了避免执行相应的信号处理函数,必须在调用该函数前,使进程屏蔽掉set指向的信号,因此调用该函数的典型代码是: 

                <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
                  <TBODY>
                  <TR>
                    <TD class=code-outline><PRE class=displaycode>sigset_t newmask;
int rcvd_sig; 
siginfo_t info;
sigemptyset(&amp;newmask);
sigaddset(&amp;newmask, SIGRTMIN);
sigprocmask(SIG_BLOCK, &amp;newmask, NULL);
rcvd_sig = sigwaitinfo(&amp;newmask, &amp;info) 
if (rcvd_sig == -1) {
	..
}
</PRE></TD></TR></TBODY></TABLE><BR>调用成功返回信号值,否则返回-1。sigtimedwait()功能相似,只不过增加了一个进程等待的时间。 
                </LI></UL>
              <LI><B>程序的稳定性。</B> <BR>为了增强程序的稳定性,在信号处理函数中应使用可重入函数。 
              <P>信号处理程序中应当使用可再入(可重入)函数(注:所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错)。因为进程在收到信号后,就将跳转到信号处理函数去接着执行。如果信号处理函数中使用了不可重入函数,那么信号处理函数可能会修改原来进程中不应该被修改的数据,这样进程从信号处理函数中返回接着执行时,可能会出现不可预料的后果。不可再入函数在信号处理函数中被视为不安全函数。</P>
              <P>满足下列条件的函数多数是不可再入的:(1)使用静态的数据结构,如getlogin(),gmtime(),getgrgid(),getgrnam(),getpwuid()以及getpwnam()等等;(2)函数实现时,调用了malloc()或者free()函数;(3)实现时使用了标准I/O函数的。The 
              Open 
              Group视下列函数为可再入的:</P><CODE>_exit()、access()、alarm()、cfgetispeed()、cfgetospeed()、cfsetispeed()、cfsetospeed()、chdir()、chmod()、chown()、close()、creat()、dup()、dup2()、execle()、execve()、fcntl()、fork()、fpathconf()、fstat()、fsync()、getegid()、 
              geteuid()、getgid()、getgroups()、getpgrp()、getpid()、getppid()、getuid()、kill()、link()、lseek()、mkdir()、mkfifo()、 
              open()、pathconf()、pause()、pipe()、raise()、read()、rename()、rmdir()、setgid()、setpgid()、setsid()、setuid()、 
              sigaction()、sigaddset()、sigdelset()、sigemptyset()、sigfillset()、sigismember()、signal()、sigpending()、sigprocmask()、sigsuspend()、sleep()、stat()、sysconf()、tcdrain()、tcflow()、tcflush()、tcgetattr()、tcgetpgrp()、tcsendbreak()、tcsetattr()、tcsetpgrp()、time()、times()、 
              umask()、uname()、unlink()、utime()、wait()、waitpid()、write()。 </CODE>
              <P>即使信号处理函数使用的都是"安全函数",同样要注意进入处理函数时,首先要保存errno的值,结束时,再恢复原值。因为,信号处理过程中,errno值随时可能被改变。另外,longjmp()以及siglongjmp()没有被列为可再入函数,因为不能保证紧接着两个函数的其它调用是安全的。</P></LI></OL><BR>
            <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD><IMG height=1 alt="" 
                  src="Linux环境进程间通信(二) 信号(下).files/blue_rule.gif" 
                  width="100%"><BR><IMG height=6 alt="" 
                  src="Linux环境进程间通信(二) 信号(下).files/c.gif" width=8 
              border=0></TD></TR></TBODY></TABLE>
            <TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
              <TBODY>
              <TR align=right>
                <TD><IMG height=4 alt="" 
                  src="Linux环境进程间通信(二) 信号(下).files/c.gif" width="100%"><BR>
                  <TABLE cellSpacing=0 cellPadding=0 border=0>
                    <TBODY>
                    <TR>
                      <TD vAlign=center><IMG height=16 alt="" 
                        src="Linux环境进程间通信(二) 信号(下).files/u_bold.gif" width=16 
                        border=0><BR></TD>
                      <TD vAlign=top align=right><A class=fbox 
                        href="http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
            <P><A name=3><SPAN class=atitle>三、深入浅出:信号应用实例</SPAN></A></P>
            <P>linux下的信号应用并没有想象的那么恐怖,程序员所要做的最多只有三件事情:</P>
            <OL>
              <LI>安装信号(推荐使用sigaction()); 
              <LI>实现三参数信号处理函数,handler(int signal,struct siginfo *info, void *); 
              <LI>发送信号,推荐使用sigqueue()。 </LI></OL>
            <P>实际上,对有些信号来说,只要安装信号就足够了(信号处理方式采用缺省或忽略)。其他可能要做的无非是与信号集相关的几种操作。</P>
            <P><B>实例一:信号发送及处理</B> <BR>实现一个信号接收程序sigreceive(其中信号安装由sigaction())。 
            </P>
            <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
              <TBODY>
              <TR>
                <TD class=code-outline><PRE class=displaycode>#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;unistd.h&gt;
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
	struct sigaction act;	
	int sig;
	sig=atoi(argv[1]);
	
	sigemptyset(&amp;act.sa_mask);
	act.sa_flags=SA_SIGINFO;
	act.sa_sigaction=new_op;
	
	if(sigaction(sig,&amp;act,NULL) &lt; 0)
	{
		printf("install sigal error\n");
	}
	
	while(1)
	{
		sleep(2);
		printf("wait for the signal\n");
	}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
	printf("receive signal %d", signum);
	sleep(5);
}
</PRE></TD></TR></TBODY></TABLE><BR>
            <P>说明,命令行参数为信号值,后台运行sigreceive signo 
            &amp;,可获得该进程的ID,假设为pid,然后再另一终端上运行kill -s signo 
            pid验证信号的发送接收及处理。同时,可验证信号的排队问题。 
            <BR><B>注:</B>可以用sigqueue实现一个命令行信号发送程序sigqueuesend,见 <A 
            href="http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html#5">附录1</A>。 
            </P>
            <P><B>实例二:信号传递附加信息</B> <BR>主要包括两个实例: </P>
            <OL>
              <LI>向进程本身发送信号,并传递指针参数; 
              <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
                <TBODY>
                <TR>
                  <TD class=code-outline><PRE class=displaycode>#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;unistd.h&gt;
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
	struct sigaction act;	
	union sigval mysigval;
	int i;
	int sig;
	pid_t pid;		
	char data[10];
	memset(data,0,sizeof(data));
	for(i=0;i &lt; 5;i++)
		data[i]='2';
	mysigval.sival_ptr=data;
	
	sig=atoi(argv[1]);
	pid=getpid();
	
	sigemptyset(&amp;act.sa_mask);
	act.sa_sigaction=new_op;//三参数信号处理函数
	act.sa_flags=SA_SIGINFO;//信息传递开关
	if(sigaction(sig,&amp;act,NULL) &lt; 0)
	{
		printf("install sigal error\n");
	}
	while(1)
	{
		sleep(2);
		printf("wait for the signal\n");
		sigqueue(pid,sig,mysigval);//向本进程发送信号,并传递附加信息
	}
}
void new_op(int signum,siginfo_t *info,void *myact)//三参数信号处理函数的实现
{
	int i;
	for(i=0;i&lt;10;i++)
	{
		printf("%c\n ",(*( (char*)((*info).si_ptr)+i)));
	}
	printf("handle signal %d over;",signum);
}
</PRE></TD></TR></TBODY></TABLE><BR>
              <P>这个例子中,信号实现了附加信息的传递,信号究竟如何对这些信息进行处理则取决于具体的应用。</P>
              <LI>2、 不同进程间传递整型参数:把1中的信号发送和接收放在两个程序中,并且在发送过程中传递整型参数。 <BR>信号接收程序: 
              <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
                <TBODY>
                <TR>
                  <TD class=code-outline><PRE class=displaycode>#include &lt;signal.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;unistd.h&gt;
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
	struct sigaction act;
	int sig;
	pid_t pid;		
	
	pid=getpid();
	sig=atoi(argv[1]);	
	
	sigemptyset(&amp;act.sa_mask);
	act.sa_sigaction=new_op;
	act.sa_flags=SA_SIGINFO;
	if(sigaction(sig,&amp;act,NULL)&lt;0)
	{
		printf("install sigal error\n");
	}
	while(1)
	{
		sleep(2);
		printf("wait for the signal\n");
	}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
	printf("the int value is %d \n",info-&gt;si_int);
}
</PRE></TD></TR></TBODY></TABLE><BR>
              <P>信号发送程序:命令行第二个参数为信号值,第三个参数为接收进程ID。</P>
              <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
                <TBODY>
                <TR>
                  <TD class=code-outline><PRE class=displaycode>#include &lt;signal.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
main(int argc,char**argv)
{
	pid_t pid;
	int signum;
	union sigval mysigval;
	signum=atoi(argv[1]);
	pid=(pid_t)atoi(argv[2]);
	mysigval.sival_int=8;//不代表具体含义,只用于说明问题
	if(sigqueue(pid,signum,mysigval)==-1)
		printf("send error\n");
	sleep(2);
}
</PRE></TD></TR></TBODY></TABLE><BR>
              <P><B>注:</B>实例2的两个例子侧重点在于用信号来传递信息,目前关于在linux下通过信号传递信息的实例非常少,倒是Unix下有一些,但传递的基本上都是关于传递一个整数,传递指针的我还没看到。我一直没有实现不同进程间的指针传递(实际上更有意义),也许在实现方法上存在问题吧,请实现者email我。 
              </P></LI></OL>
            <P><B>实例三:信号阻塞及信号集操作</B> </P>
            <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
              <TBODY>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?