Linux进程通信(2):信号(上)

一、信号概念

信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间通信机制中唯一的异步通信机制,可以

看作是异步通知,通知接收信号的进程有哪些事情发生了.信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息.

二、信号的使用

2.1 信号的安装
#include <signal.h>
void (*signal(int signum, void (*handler))(int)))(int);
功能:实现信号和信号处理函数的绑定
举例:signal(SIGUSR1,func);

#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
参数:signum信号值;可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号
参数:act信号的处理设置;其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
参数:oldact信号以前的设置

struct sigaction {
       union{
            __sighandler_t _sa_handler;//信号处理函数或者SIG_DEL、SIG_IGN
            void (*_sa_sigaction)(int,struct siginfo *, void *);//带参数的信号处理函数
            }_u
       sigset_t sa_mask;//信号处理程序执行过程中,哪些信号应当被阻塞,缺省情况下当前信号本身被阻塞,防止信号的嵌套发送
       unsigned long sa_flags;//标志
       void (*sa_restorer)(void);
                 }
sa_flags常用值如下:
SA_NODEFER
SA_NOMASK    消息处理期间,不屏蔽本身
SA_SIGINFO   信号附带数据
SA_RESETHAND 消息处理重置

 2.2 信号的发送

发送信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort().

int kill()
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid,int signo)
参数:pid信号的接收进程
pid>0 进程ID为pid的进程
pid=0 同一个进程组的进程
pid<0 pid!=-1 进程组ID为 -pid的所有进程
pid=-1 除发送进程自身外,所有进程ID大于1的进程
参数:signo是信号值,当为0时(即空信号),实际不发送任何信号,但照常进行错误检查,因此,可用于检查目标进程是否存在,以及当前进程是否具有向目标发送信号的权限(

root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程发送信号).
返回值:成功返回 0; 否则返回 -1
 
#include <signal.h>
int raise(int signo)
向进程本身发送信号
参数:signo为即将发送的信号值
返回值:调用成功返回 0;否则,返回 -1.

#include <sys/types.h>
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval val)
参数:pid信号的接收进程
参数:sig信号值
参数:val附加的消息
返回值:调用成功返回 0;否则,返回 -1.
sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然也支持前32种),支持信号带有参数,与函数sigaction()配合使用.

typedef union sigval {
  int  sival_int;
  void *sival_ptr;
 }sigval_t;
sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组.

int alarm()
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
功能:在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间.进程调用alarm后,任何以前的alarm()调用都将无效.如果参数seconds为零,那么进程内将

不再包含任何闹钟时间.
参数:seconds闹钟时间
返回值:如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0.

int setitimer()
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
参数: which定时器类型
setitimer()比alarm功能强大,支持3种类型的定时器:
ITIMER_REAL: 设定绝对时间;经过指定的时间后,内核将发送SIGALRM信号给本进程;
ITIMER_VIRTUAL 设定程序执行时间;经过指定的时间后,内核将发送SIGVTALRM信号给本进程;
ITIMER_PROF 设定进程执行以及内核因本进程而消耗的时间和,经过指定的时间后,内核将发送ITIMER_VIRTUAL信号给本进程;
参数:value定时器时间
参数:ovalue定时器以前的时间
返回值:成功返回0,否则返回-1.

int abort()
#include <stdlib.h>
void abort(void);
功能:向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数.即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接

收.该函数无返回值.

2.3 信号的响应

进程可以通过三种方式来响应一个信号:(1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP;(2)捕捉信号.定义信号处理函数,当信号发生时,执行相应的处理函数;(3)执行缺省操作,Linux对每种信号都规定了默认操作,详细情况请参考[2]以及其它资料.注意,进程对实时信号的缺省反应是进程终止.Linux究竟采用上述三种方式的哪一个来响应信号,取决于传递给相应API函数的参数.

三、应用举例

实例1:实现一个信号接收程序

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
	struct sigaction act;	
	int sig;
	sig=atoi(argv[1]);
	
	sigemptyset(&act.sa_mask);
	act.sa_flags=SA_SIGINFO;
	act.sa_sigaction=new_op;
	
	if(sigaction(sig,&act,NULL) < 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);
}


实例2:信号传递附加信息

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
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 <10;i++)
	     data[i]='2';
	mysigval.sival_ptr=data;
	
	sig=atoi(argv[1]);
	pid=getpid();
	
	sigemptyset(&act.sa_mask);
	act.sa_sigaction=new_op;//参数信号处理函数
	act.sa_flags=SA_SIGINFO;//信息传递开关
	if(sigaction(sig,&act,NULL) < 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<10;i++)
	{
		printf("%c\n ",(*( (char*)((*info).si_ptr)+i)));
	}
	printf("handle signal %d over;",signum);
}

参考文章:

http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值