2013-07-12 97 views
2

我有一个非常简单的线程:它将保持活动的数据包发送到服务器,然后休眠。我希望我的主线程能够指示线程退出,但每当我调用pthread_kill()时,它似乎都会使我的进程崩溃。Posix线程:发信号在while循环中运行的线程

我试着在我的while循环的开头调用sigpending()后面跟着sigismember(),但我认为它崩溃了,因为它不知道任何处理信号的问题(我正在使用sigaddset ()之前while循环),如下图:

void* foo(void* arg) 
{ 
    sigset_t set, isSignal; 

    sigemptyset(&set); 
    if (sigaddset(&set, SIGUSR1) == -1) { /* ... */ } 

    while (1) { 
     if (sigpending(&isSignal) != 0) { /* .. */ } 
     else if (sigismember(&isSignal, SIGUSR1)) { 
      break; 
     } 

     sendKeepAlive(); 
     sleep(SECONDS); 
    } 
    return NULL; 
} 

看来pthread_kill(PTH,SIGUSR1);使程序死亡。什么是正确的方式发送信号?我应该使用pthread_sigmask()吗?

回答

4

信号正在等待它是由操作系统交付的,但是一个进程或线程有被阻止了它。如果你没有阻止SIGUSR1,那么它将被交付,并且SIGUSR1的默认处置是终止该进程。你的sigpending在这种情况下什么也不做;它被有效地绕过。无论是SIGUSR1首先与pthread_sigmask或(可选)处理它。

总之这是一个可疑的设计。对于阻塞/签署代码,根据SECONDS设置的时间长短,您仍然可能需要等待很长时间才能让线程循环发现它是关闭的时间。如果你真的想为此使用信号,我会建议建立一个设置开关的信号处理程序。当SIGUSR1交付时,处理程序将被调用,它设置开关,sleep将被信号中断,您检查EINTR并立即循环检查开关,然后执行pthread_exit

选项1(在Linux编译)

#define _POSIX_C_SOURCE 2 

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <time.h> 
#include <signal.h> 

void* foo(void* arg) 
{ 
    sigset_t set, isSignal, allSigs; 

    sigfillset(&allSigs); 

    if (sigprocmask(SIG_SETMASK, &allSigs, NULL) == -1) 
    { 
     printf("sigprocmask: %m\n"); 
     exit(1); 
    } 

    sigemptyset(&set); 

    if (sigaddset(&set, SIGUSR1) == -1) 
    { 
     printf("sigaddset: %m\n"); 
     exit(1); 
    } 

    while (1) 
    { 
     if (sigpending(&isSignal) != 0) 
     { 
      printf("sigpending: %m\n"); 
      exit(1); 
     } 
     else 
      if (sigismember(&isSignal, SIGUSR1)) 
      { 
       printf("signal pending for thread, exiting\n"); 
       break; 
      } 

     printf("Doing groovy thread stuff...\n"); 

     sleep(2); 
    } 

    return NULL; 
} 


int main(int argc, char *argv[]) 
{ 
    pthread_t tid; 
    int rc; 

    rc = pthread_create(&tid, NULL, foo, NULL); 

    if (rc) 
    { 
     printf("pthread_create: %m\n"); 
     exit(1); 
    } 

    sleep(10); 

    pthread_kill(tid, SIGUSR1); 

    pthread_join(tid, NULL); 

} 

选项2(在Linux编译)

#define _POSIX_C_SOURCE 2 

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <time.h> 
#include <signal.h> 

volatile int stop = 0; 

void handler(int sig) 
{ 
    stop = 1; 
} 

void* foo(void* arg) 
{ 
    signal(SIGUSR1, handler); //use sigaction, i'm too lazy here 

    while (! stop) 
    { 
     printf("Doing groovy thread stuff...\n"); 

     if (sleep(4) > 0) 
      if (errno == EINTR) 
      { 
       printf("sleep interrupted, exiting thread...\n"); 
       continue; 
      } 
    } 

    return NULL; 
} 


int main(int argc, char *argv[]) 
{ 
    pthread_t tid; 
    int rc; 

    rc = pthread_create(&tid, NULL, foo, NULL); 

    if (rc) 
    { 
     printf("pthread_create: %m\n"); 
     exit(1); 
    } 

    sleep(10); 

    pthread_kill(tid, SIGUSR1); 

    pthread_join(tid, NULL); 

} 

选项3使用,如果你能一些其他机制。建议。

+0

谢谢你,选项2对我来说真的很好,我同意,当EINTR时我打断睡眠并退出是很好的。我非常喜欢这个解决方案,谢谢! – user1777907