天天看点

信号发送函数---kill(),raise(),alarm()

信号发送

(1)除了内核和超级用户,并不是每个进程都可以向其他的进程发送信号;

(2)一般的进程只能向具有相同uid个gid的进程发送信号,或向相同进程组中的其他进程发送信号;

(3)常用的发送信号的函数有:kill(),raise(),alarm(),setitimer(),abort()等;

kill和raise函数

#include <signal.h>

int kill(pid_t pid, int signo);

返回:成功返回0,出错返回-1;

功能:向指定的进程发送个某一个信号;

int raise(int signo);

返回:成功返回0,出错返回-1;

功能:向进程本身发送一个信号,相当于kill(getpid(), sig)

参数:pid:接受信号进程的pid

            signo:要发送的信号值

kill函数将信号发送给进程或进程组;

kill函数的pid取值:

       pid > 0     将信号发送给进程ID为pid的进程;

       pid == 0   将信号发送给与发送进程同一进程组的所有进程;

       pid < 0     将信号发送给进程组ID等于pid的绝对值的所有进程;(杀死同一进程组中的所有进程:kill -9 -进程组号),不要忘记进程组号前的负号

       pid == -1  将信号发送给发送进程有权限向他们发送信号的系统上的所有进程;

下面给出具体实例。

#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

// 定义信号处理函数
// signo:进程捕获到的信号编号
void sig_handler(int signo)
{
	printf("%d, %d occured\n", getpid(), signo);
}

int main(void)
{
	// 向内核登记信号处理函数以及信号值
	// SIGTSTP是ctrl+z,编号为20
	if(signal(SIGTSTP, sig_handler) == SIG_ERR)
	{
		perror("signal sigtstp error");
	}

	// ctrl+c,SIGINT编号为2
	if(signal(SIGINT, sig_handler) == SIG_ERR)
	{
		perror("signal sigint error");
	}
	if(signal(SIGUSR1, sig_handler) == SIG_ERR)
	{
		perror("signal sigusr1 error");
	}
	if(signal(SIGUSR2, sig_handler) == SIG_ERR)
	{
		perror("signal sigusr2 error");
	}

	//SIGKILL不能忽略(SIG_IGN)也不能捕获
/*	if(signal(SIGKILL, SIG_DFL) == SIG_ERR)
	{
		perror("signal sigkill error");
	}
	if(signal(SIGSTOP, SIG_DFL) == SIG_ERR)
	{
		perror("signal sigstop error");
	}	
*/
	int i = 0;
	while(i < 20)
	{
		printf("%d out %d\n", getpid(), i++);
	/*	if(i == 5)
			raise(SIGKILL);*/
		sleep(1);
	}
	
	// 10s以后进程向自己发送SIGUSR1和SIGUSR2
	raise(SIGUSR1);
	kill(getpid(), SIGUSR2);
	return 0;
}
           

alarm函数

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

返回:0或者以前设置的定时器时间余留的秒数;

alarm函数可设置定时器,当定时器超时,产生SIGALRM信号;

信号由内核产生,在指定的seconds秒之后,给进程本身发送一个SIGALRM信号;

参数为0,则取消以前设置的定时器;

#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

// 信号处理函数
void sig_handler(int signo)
{
	if(signo == SIGALRM)
	{
		printf("clock time out\n");
		// 重新设置定时器(周期性的定时)
		alarm(5);
	}
}

void out_data(void)
{
	int i = 1;
	while(i <= 23)
	{
		double d = drand48();
		printf("%-10d:%lf\n", i++, d);
/*		if(i == 13)
			alarm(0); // 取消之前设置的定时器
*/
		sleep(1);
	}
}

int main(void)
{
	if(signal(SIGALRM, sig_handler) == SIG_ERR)
	{
		perror("signal sigalrm error");
	}

	// 设置定时器
	alarm(5);
	printf("begin running main\n");
	out_data();
	printf("end running main\n");

	return 0;
}
           

上述代码中,在第一个alarm(5),输出第5个数后,进程给自己发送了SIGALRM信号,触发信号处理函数,这时如果sig_handler函数中没有重新设置新的定时器,则此后不再会计时;程序中在sig_handler中设置了定时器,那么此后还是每隔5s就会重新设置一次定时器;

另外注意,在程序中有一句alarm(0),这里的意思也就是在13秒之后会取消上一个设置的定时器,此后也不再进行计时。

继续阅读