现在的位置: 首页 > 综合 > 正文

linux signal学习

2014年05月24日 ⁄ 综合 ⁄ 共 4208字 ⁄ 字号 评论关闭

本文只总结signal的应用,对signal的kernel实现暂不讨论。

1. linux signal是什么?
signal是linux提供的用于进程间通信的一种IPC机制。

2. 如何发送signal来实现IPC?
使用kill命令或kill函数可以发指定的进程发送signal。
kill -0 pid,没有id为0的signal,通常这个命令仅仅是用来测试进程号为pid对应的进程是否存在;
不过使用ps -A | grep pid应该同样可以做这项测试。
kill -9 pid,强制杀掉一个进程。
对于linux管理员来讲,经常会搭配ps/pstree/top等命令来查找系统中异常的进程并将其杀死。
kill pid,如果没有指定某个signal,那默认会送SIGTERM给pid对应的进程。

3. signal被如何处理?
#include <signal.h>
signal通常有三种处理方式:
(1)显示的ignore,
signal(SIGTSTP, SIGIGN);
这样子的话你的进程就会收到这条signal,但是处理的方式是ignore;
(2)你的进程可能会对某个特定的signal感兴趣,这时就可以捕获这个signal并去处理它,
struct sigaction t_act, t_oldact;
t_act.sa_flags = SA_NODEFER;
t_act.sa_sigaction = _my_signal_hander;
sigaction(SIGUSR1, &t_act, &t_oldact);
static void _my_signal_handler()
{
    /* do your thing */
}
(3)按照默认的方式处理,这样kernel会按照已经预设好的流程来处理这个signal。

4. 如何确定每一条signal对应的num,比如SIGUSR1对应的num值是多少?
请看signal.h这个header file
#define SIGHUP 1
#define SIGUSR1 10
在shell下面kill -10 pid与kill SIGUSR1 pid作用是一样的。

5. signal的应用?
#include <signal.h>

static void _my_signal_hander(int signal, siginfo_t* pt_info, void* pv_ctx)
{
    if (SIGUSR1 == signal)
    {
        printf("\n_my_signal_hander, SIGUSR1\n");
    }
    else if (SIGUSR2 == signal)
    {
        printf("\n_my_signal_hander, SIGUSR2\n");
    }
}

int main(void)
{
    struct sigaction t_act, t_old_act;
  t_act.sa_flags = SA_NODEFER | SA_SIGINFO;
  t_act.sa_sigaction = _my_signal_hander;
  sigaction(SIGUSR1, &t_act, &t_oldact);
  sigaction(SIGUSR2, &t_act, &t_oldact);
 
  exit(0);
}

待解决问题:
为什么在linux shell下面用kill SIGUSR1 pid送signal给pid这个process,系统会挂掉;
但是在代码中使用kill(pid, SIGUSR1);则可以成功的发送SIGUSR1给pid呢?

问题已解决,原因是我的系统shell下不能识别SIGUSR1这种写法的signal,
所以只能查找<signal.h>这个header file,从中找到对应signal的数值,再发送signal就没问题了。
当然我也实验了其它的linux系统,发现kill -SIGINT pid这种写法就没问题,
这个不是暂时的重点,后续有机会了解到其原因时再补充上来。
sh-# kill -10 484
_sig_action
_sig_action, SIGUSR1
sh-# kill -12 484
_sig_action
_sig_action, SIGUSR2
sh-# kill -SIGUSR1 484
sh: kill: SIGUSR1: invalid signal specification
sh-# kill SIGUSR1 484
sh: kill: `SIGUSR1': not a pid or valid job spec

2013/10/08更新:
可以使用kill -l来查看当前shell所识别的signal符号名,这样就可以直接发送信号了。
sh-# kill -l
HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS
sh-# kill -CHLD 7710
sh-# echo $?
0
sh-#
sh-# kill -HUP 7710
Hangup
INIT: Entering runlevel: 3

在所有这些signal中,SIGKILL和SIGSTOP是很特殊的。
这两个signal既不能被ignore,也不能被block,而且用户也不能去capture,
当这两条signal产生时,系统总是会执行它们的默认行为。
除此之外的其它signal都可以被用户程序capture到,这样用户程序可以根据
需要在收到特定signal时做特定的事。

6. signal函数的使用示例?
void (*signal)(int signum, void(* handler)(int)))(int);

signal函数的原型看起来太复杂,这里不想讨论,只对signal的功能和用法感兴趣。
signal函数能干的事有:
(1)使用signal函数来接管感兴趣的signal;
(2)ignore指定的信号,不希望该信号被内核以默认的方式处理同时自己也不会特别处理;
(3)恢复signal的默认执行动作。

下面的例子是程序忽略对SIGUSR1的处理,同时监听SIGUSR2并在收到SIGUSR2时做特定的动作,
最后做完后恢复SIGUSR2的默认处理动作。
#include <signal.h>
static void _signal_handler(int sig_num)
{
    if (SIGUSR2 == sig_num)
    {
        printf("\nreceived SIGUSR2\n");
        do_something();
        signal(SIGUSR2, SIGDFL);
    }
}

int main(void)
{
    signal(SIGUSR1, SIGIGN);
    signal(SIGUSR2, _signal_handler);
}

待解决问题:
7. 如何阻塞一个signal?
有时候程序可能需要暂时性的去block一个signal,直到某件事做完,再去unblock这个signal。
所谓block一个signal就是这个signal在unblock之前一直不会被处理到。
所以紧接着本人写了一小段测试代码来验证这个东西。
#include <signal.h>

static void _signal_handler(int signal_num)
{
    if (SIGUSR1 == signal_num)
    {
        fprintf((void*)1, "\n_signal_handler, SIGUSR1\n");
    }
    else if (SIGUSR2 == signal_num)
    {
        fprintf((void*)1, "\n_signal_handler, SIGUSR2\n");
    }
}

int main()
{
    sigset_t signalmask;
    signal(SIGUSR1, _signal_handler);
    signal(SIGUSR2, _signal_handler);
   
    sigempty(&signalmask);
    sigaddset(&signalmask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &signalmask, null);
   
    sleep(100);
   
    sigprocmask(SIG_UNBLOCK, &signalmask, null);
}
预期的行为是SIGUSR1因为先被阻塞住,所以我在shell下面输入
kill -10 pid
开始时SIGUSR1不会被我的程序处理到。等到100s之后因为SIGUSR1被unblock了,
然后程序才会去处理之前block的那个signal。而SIGUSR2总会被我的程序处理到。
但实验结果是,并没有像我预期的那样,也就是这段代码没能block住SIGUSR1,
这是为什么呢?是我用错了吗?
等有答案时再将实验结果补上来。
2013/11/11补充,
写了如下一段测试代码,看起来signal block应该是有用的;
只是关于signal的更多内容,需要在使用时再详细学习了。

#include <stdio.h>
#include <signal.h>

static void _signal_handler(int signal_num)
{
    printf("\nsignal_num=%d", signal_num);
    return;
}

int main(int argc, char *argv[])
{
    sigset_t signalmask;
   
    signal(SIGUSR1, _signal_handler);
    signal(SIGUSR2, _signal_handler);
   
    sigemptyset(&signalmask);
    sigaddset(&signalmask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &signalmask, (void*)0);
    sleep(100);
    sigprocmask(SIG_UNBLOCK, &signalmask, (void*)0);
   
    while(1)
    {
        sleep(1);
    }
   
    exit(0);
}

抱歉!评论已关闭.