线程号仅在进程内可用且,使用另一进程内的线程号时其行为未定义。当对线程调用pthread_join()成功或已分离线程终止后,该线程生命周期结束,其线程号不再有效(可能已被新线程重用)。程序试图使用该无效线程号时,其行为未定义。标准并未限制具体实现中如何定义pthread_t类型,而该类型可能被定义为指针,当其指向的内存已被释放时,对线程号的访问将导致程序崩溃。因此,通过pthread_kill()测试已分离的线程时,也存在与kill()相似的局限性。仅当未分离线程退出但不被回收(join)时,才能期望pthread_kill()必然返回ESRCH错误。同理,通过pthread_cancel()取消线程时也不安全。
  若要避免无效线程号的问题,线程退出时不应直接调用pthread_kill(),而应按照如下步骤:
  1) 为每个线程维护一个Running标志和相应的互斥量;
  2) 创建线程时,在新线程启动例程ThrdFunc内设置Running标志为真;
  3) 从新线程启动例程ThrdFunc返回(return)、退出(pthread_exit)前,或在响应取消请求时的清理函数内,获取互斥量并设置Running标志为假,再释放互斥量并继续;
  4) 其他线程先获取目标线程的互斥量,若Running标志为真则调用pthread_kill(),然后释放互斥量。
  信号发送成功后,信号处理函数会在指定线程的上下文中执行。若该线程未注册信号处理函数,则该信号的默认处理动作将影响整个进程。当信号默认动作是终止进程时,将信号发送给某个线程仍然会杀掉整个进程。因此,信号值非0时必须实现线程的信号处理函数,否则调用pthread_kill()将毫无意义。
  三  示例
  本节将通过一组基于NPTL线程库的代码示例,展示多线程环境中信号处理的若干细节。
  首先定义两个信号处理函数:

 

1 static void SigHandler(int dwSigNo)
2 {
3     printf("++Thread %x Received Signal %2d(%s)! ",
4            (unsigned int)pthread_self(), dwSigNo, strsignal(dwSigNo));
5 }
6 static void sighandler(int dwSigNo)
7 {   //非异步信号安全,仅为示例
8     printf("--Thread %x Received Signal %2d(%s)! ",
9            (unsigned int)pthread_self(), dwSigNo, strsignal(dwSigNo));
10 }

  其中,SigHandler()用于同步处理,sighandler()则用于同步处理。
  3.1 示例1
  本示例对比单线程中,sigwait()和sigwaitinfo()函数的可中断性。

 

1intmain(void)
2{
3sigset_ttBlockSigs;
4sigemptyset(&tBlockSigs);
5sigaddset(&tBlockSigs,SIGINT);
6sigprocmask(SIG_BLOCK,&tBlockSigs,NULL);
7
8signal(SIGQUIT,sighandler);
9
10intdwRet;
11#ifdefUSE_SIGWAIT
12intdwSigNo;
13dwRet=sigwait(&tBlockSigs,&dwSigNo);
14printf("sigwaitreturns%d(%s),signo=%d ",dwRet,strerror(errno),dwSigNo);
15#else
16siginfo_ttSigInfo;
17dwRet=sigwaitinfo(&tBlockSigs,&tSigInfo);
18printf("sigwaitinforeturns%d(%s),signo=%d ",dwRet,strerror(errno),tSigInfo.si_signo);
19#endif
20
21return0;
22}

  编译链接(加-pthread选项)后,执行结果如下: