信号发送
(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秒之后会取消上一个设置的定时器,此后也不再进行计时。