信号究竟发给谁
信号究竟发给谁
Linux中进程和线程本是一个东西,在内核中都是由task_struct结构标示。
两者都是由do_fork内核函数来启动,只是调用do_fork的参数不同。
如果进程只有一个线程,那么发给该进程的信号显然只能发给这个线程;
信号和信号处理函数是进程资源,那么当进程有多个线程时,信号究竟发给谁呢?
我做了3个实验来探讨这个问题,实验所采用的平台如下:
OS: fedora 11
kernel: 2.6.29.4-167.fc11.i686.PAE
gcc: (GCC) 4.4.0 20090506 (Red Hat 4.4.0-4)
编译命令:gcc -g -W -Wall -Wextra -o mytest main.c -lpthread
实验1
首先用下面的代码作测试
main.c:
========================================
// 2011年 11月 29日 星期二 08:37:06 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
void *work_thread(void *);
void work();
void handler(int);
int main()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGQUIT, &sa, 0);
pthread_t tid;
pthread_create(&tid, 0, work_thread, 0);
work();
return 0;
}
void handler(int s)
{
char buf[32];
snprintf(buf, sizeof(buf), "\n%ld recv signal", syscall(SYS_gettid));
psignal(s, buf);
}
void *work_thread(void *p)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
work();
return (void *)0;
}
void work()
{
for(;;) {
pause();
fprintf(stderr, "I\'m Zuro %ld\n", syscall(SYS_gettid));
}
}
===========================================================
我在主线程里注册SIGQUIT信号处理函数,在另一个线程里注册SIGINT信号处理函数,
但是当我执行该程序时无论我在终端键入Ctrl-C(发送SIGINT信号)
还是Ctrl-\(发送SIGQUIT信号),信号都是发给主线程!
程序输出如下:
=========================================
^C
2536 recv signal: Interrupt
I'm Zuro 2536
^C
2536 recv signal: Interrupt
I'm Zuro 2536
^\
2536 recv signal: Quit
I'm Zuro 2536
^\
2536 recv signal: Quit
I'm Zuro 2536
==========================================
用kill命令杀死这个进程。
实验2
我把上面的程序修改一下:
main.c:
=============================================
// 2011年 11月 29日 星期二 08:37:06 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
void *work_thread(void *);
void work();
void handler(int);
int main()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
//sigaction(SIGQUIT, &sa, 0);
sigaction(SIGSEGV, &sa, 0);
pthread_t tid;
pthread_create(&tid, 0, work_thread, 0);
work();
return 0;
}
void handler(int s)
{
char buf[32];
snprintf(buf, sizeof(buf), "\n%ld recv signal", syscall(SYS_gettid));
psignal(s, buf);
}
void *work_thread(void *p)
{
for(;;) {
fprintf(stderr, "I\'m Zuro %ld\n", syscall(SYS_gettid));
sleep(2);
char *p = 0;
*p = 'a';
}
return (void *)0;
}
void work()
{
for(;;) {
pause();
fprintf(stderr, "I\'m Zuro %ld\n", syscall(SYS_gettid));
}
}
=====================================================================
现在我在主线程里注册SIGSEGV信号处理函数,而在另一个线程里产生一个SIGSEGV信号。
编译执行,等一段时间后Ctrl-C终止该进程。发现这时信号不再发送给主线程,
而是发送给产生SIGSEGV信号的那个线程!
实验3
我再把代码作一下修改:
main.c:
=======================================================
// 2011年 11月 29日 星期二 08:37:06 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
void *work_thread(void *);
void work();
void handler(int);
int main()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGQUIT, &sa, 0);
pthread_t tid;
pthread_create(&tid, 0, work_thread, 0);
work();
return 0;
}
void handler(int s)
{
char buf[32];
snprintf(buf, sizeof(buf), "\n%ld recv signal", syscall(SYS_gettid));
psignal(s, buf);
}
void *work_thread(void *p)
{
/*struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);*/
for(;;) {
fprintf(stderr, "I\'m Zuro %ld\n", syscall(SYS_gettid));
sleep(2);
raise(SIGQUIT);
}
return (void *)0;
}
void work()
{
for(;;) {
pause();
fprintf(stderr, "I\'m Zuro %ld\n", syscall(SYS_gettid));
}
}
=================================
补充:软件开发 , C语言 ,