我有一个非常简单的线程:它将keep-alive数据包发送到服务器,然后休眠。我希望我的主线程能够通知线程退出,但每当我调用pthread_kill()时,它似乎都会导致我的进程崩溃。
我尝试在我的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()吗?
答案 0 :(得分:4)
当操作系统发出信号但进程或线程已阻止时,信号处于挂起状态。如果您尚未阻止SIGUSR1,那么它将被交付,SIGUSR1的默认处置是终止该进程。你的sigpending
在这种情况下什么都不做;它被有效地绕过了。首先用pthread_sigmask
阻止SIGUSR1或(可选)处理它。
总之,这是一个可疑的设计。使用阻塞/ sigpending代码,根据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 如果可以,请使用其他一些机制。宜。
答案 1 :(得分:2)
我会丢失信号,只使用pthread条件变量,例如pthread_cond_timedwait()):
... IMHO