`
sunzixun
  • 浏览: 74856 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Liunx NPTL 杂谈(1)--线程信号处理

阅读更多

本教程不是基础线程,希望有点基础的POSIX 线程知识。 高手也不用看了。。

第一篇:Linux线程的信号处理行为

大家都知道linux 2.5内核之后 引入了NPTL ,让自己的用户态线程行为更符合Poxis口味。。下面就来看看NPTL的线程对信号的行为。

当然我们得首先复习..几个linux上的函数

tkill 
NAME tkill
 - send a signal to a single process SYNOPSIS int tkill(int tid, int sig); 
DESCRIPTION
 The tkill() system call is analogous to kill(2), except when the specified process is part of a thread group (created by specifying the CLONE_THREAD flag in the call to clone). Since all the processes in a thread group have the same PID, they cannot be individually sig-nalled with kill(2). With tkill(), however, one can address each process by its unique TID.These are the raw system call interfaces, meant for internal thread library use.

 
我个人感觉这个man写的不怎么好: 因为你不能把他翻译成中文去理解

通俗易懂的说: tkill 可以发给特定的 LWP,比如一个进程,他产生了很多LWP, 那么我可以想发给谁发给谁。
如果他不产生,就他一个独苗,那么我用tikll对他发信号,和kill发效果是一样的。 

我们都知道如果通过kill 发信号给一个PID ,如果你没有做什么的话,正常情况下,应该是main线程接受。这个时候你会想,太搓了! 我要把信号发给我指定的人!
好linux知道你有这个怪癖,提供了tkill。 问题来了 tid是啥。。2.6内核proc下面看不到了!当然你可以猜:
现在的进程是 PID, 那么我产生的应该是 PID+1,但是当你产生了1000个,就找不到北了。。 
linux当然早提供了gettid ,你可能需要通过

syscall(SYS_gettid);

记住 pthread_self 得到是线程自己的一个pthread_t ,这个玩意内核是没有数据结构记录的,应该只是一个用户态的东东,对他发信号,只需要 pthread_kill();
这个时候,你是不是开始跃跃欲试的,想试试看 tkill了? 于是你会这样写

测试进程:

static void* is_receive(void* arg)
{
	while(1) {
		printf("%d LWP  RUNNING\n",
				syscall(SYS_gettid);	);
		sleep(5);
	}
	return (void*)(-1);
}

int main(int argc, char *argv[])
{
	pthread_t t;
	pthread_attr_t prattr;
	pthread_attr_init(&prattr);
	pthread_attr_setdetachstate(&prattr,
			PTHREAD_CREATE_JOINABLE);
	pthread_attr_setscope(&prattr, PTHREAD_SCOPE_SYSTEM);
	pthread_create(&t, &prattr, is_receive, NULL);
	pause();
}

 
然后很开心的用

syscall(__NR_tkill, tid, SIGUSR1);

发送完了,你ps -ef一看,说,cao 。。不对啊,主线程也没了。
记住,如果你用任何测试信号的时候。 请记得他在 APUE书中写的默认行为 ,改整个进程退出的他们还是会退出,不是你发给 某个LWP,就可以改变Poxis的。。

所以你最好找那种默认行为为SIG_IGN的测试。。或者你自己之前改写了如SIGPIPE这样的信号行为。
于是你会得到你想要的结果。
然后你会说,我不想用tkill ,因为是custom 发信息给我。他不知道TID,只知道PID。这个时候你只能用kill(sigqueue)
于是谁去处理信号的问题,就需要你编程手动处理。

我们先来看看thread prime上怎么说:

 

我觉得T_P上面很多话都没用。 关于这个话题我提炼出一句话:  你需要发给哪个LWP ,把不需要的BLOCK就行!
代码看起来可能应该这样写。

void block_it(int sig)
{
	sigset_t sig_block;
	sigemptyset(&sig_block);
	sigaddset( &sig_block, sig);
	sigprocmask( SIG_BLOCK, &sig_block, NULL );
	//pthread_sigmask( SIG_BLOCK, &sig_block, NULL );
}

static void* receive_signal(void* arg)
{
	//block_it(SIGUSR2);
	while(1) {
		sleep(5);
	}
	return (void*)(-1);
}

static void just_printf(int arg){
	printf("%d RECEIVING\n",syscall(SYS_gettid));
}

int main(int argc, char *argv[])
{
	signal(SIGUSR2,just_printf);
	int tid;
	pthread_t t;
	pthread_attr_t prattr;
	pthread_attr_init(&prattr);
	pthread_attr_setdetachstate(&prattr,PTHREAD_CREATE_JOINABLE);
	pthread_attr_setscope(&prattr, PTHREAD_SCOPE_SYSTEM);
	pthread_create(&t, &prattr, receive_signal, NULL);
	block_it(SIGUSR2);//让子线程接受信号
	pause();
}

 



看到block_it 这个函数了吗? 没错。just do it, 在信号来之前赶快哦。 这样你用kill(getpid(),SIG___) 你会发现他们工作的很好。 就算你个pid发送,子线程也帮你处理了这个信号~。


方法告诉你了,具体几千个LWP怎么指派某一个,就要自己发挥想象啦。 P_T中告诉你。。你可以用一个专门的信号处理线程~~

同样你也可能看到注释掉的pthread_sigmask() 为啥呢。因为

 The function shall be equivalent to sigprocmask(), without  the restriction that the call be made in a single-threaded process.

 
大家考虑一下,怎么实现一个异步IO ? 

 

 

 

>

>

>

>

 

没错 ,如果了解 softirq 的人 都知道通过 参考ksoftirqd  线程

A: dedicated kernel<use process> thread ; B : work queues 在加上上面说的唤醒锁机制 就ok 啦 

 

 

 

 

 

  • 大小: 28.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics