【问题标题】:Posix threads:Signal a thread that is running in while loopPosix 线程:发出一个在 while 循环中运行的线程的信号
【发布时间】:2013-07-12 02:59:10
【问题描述】:

我有一个非常简单的线程:它将保持活动的数据包发送到服务器,然后休眠。我希望我的主线程向线程发出退出信号,但是每当我调用 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() 吗?

【问题讨论】:

    标签: multithreading unix pthreads signals posix


    【解决方案1】:

    当信号由操作系统传递但进程或线程已阻塞时,信号处于未决状态。如果您没有阻止 SIGUSR1,那么它将被交付,并且 SIGUSR1 的默认处置是终止进程。您的sigpending 在这种情况下什么也不做;它被有效地绕过了。要么首先使用pthread_sigmask 阻止 SIGUSR1,要么(可选)处理它。

    总的来说,这是一个可疑的设计。使用阻塞/正在等待的代码,根据 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 如果可以,请使用其他机制。建议。

    【讨论】:

    • 谢谢,选项 2 对我来说非常有效,我同意,在 EINTR 时中断睡眠并退出很好。我真的很喜欢这个解决方案,谢谢!
    【解决方案2】:

    我会丢失信号,只使用 pthread 条件变量,例如 pthread_cond_timedwait()):

    恕我直言...

    【讨论】:

      猜你喜欢
      • 2012-10-28
      • 1970-01-01
      • 2021-09-14
      • 2021-02-09
      • 2011-02-04
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多