2

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

我试图在我的 while 循环开始时调用 sigpending(),然后是 sigismember(),但我认为它正在崩溃,因为它不知道任何处理信号的句柄(我在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

2 回答 2

5

当信号由操作系统传递但进程或线程阻止它时,信号处于未决状态。如果您没有阻止 SIGUSR1,那么它将被交付,并且 SIGUSR1 的默认处置是终止进程。在这种情况下,您sigpending什么都不做;它被有效地绕过了。首先阻止 SIGUSR1pthread_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 如果可以,请使用其他机制。建议。

于 2013-07-12T03:44:16.010 回答
2

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

恕我直言...

于 2013-07-12T03:18:52.170 回答