Posix线程:向在while循环中运行的线程发出信号 [英] Posix threads:Signal a thread that is running in while loop

查看:91
本文介绍了Posix线程:向在while循环中运行的线程发出信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a thread that is a very simple: it sends keep-alive packets to a server, then sleeps. I would like my main thread to signal the thread to quit, but whenever I call pthread_kill() it seems to crash my process.

我尝试在while循环的开头调用sigpending(),然后调用sigismember(),但我认为它崩溃了,因为它不知道任何处理信号的句柄(我在使用sigaddset( )在while循环之前),如下:

I tried to call sigpending() followed by sigismember() at the beginning of my while loop, but I think it is crashing because it doesn't know of any handle to take care of the signal (I was using sigaddset() before the while loop), as follow:

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()吗?

It seems pthread_kill(pth, SIGUSR1); makes the program dies. What is the right way to send the signal please? Should I use pthread_sigmask() instead?

推荐答案

当信号由OS传递但进程或线程已阻塞时,该信号处于挂起状态.如果您尚未阻止SIGUSR1,则它将被交付,并且SIGUSR1的默认配置是终止该过程.您的sigpending在这种情况下什么也不做;它被有效地绕过了.首先使用pthread_sigmask阻止SIGUSR1或(可选)对其进行处理.

A signal is pending when it is delivered by the OS but a process or thread has blocked it. If you haven't blocked SIGUSR1 then it is going to be delivered and the default disposition of SIGUSR1 is to terminate the process. Your sigpending is doing nothing in this scenario; it is effectively bypassed. Either block SIGUSR1 first with pthread_sigmask or (optionally) handle it.

总的来说,这是一个可疑的设计.使用被阻止/发送的代码,根据SECONDS设置的时间长短,您仍然可以等待很长时间,直到线程环回,才知道该关闭了.如果您真的想为此使用信号,建议您建立一个设置开关的信号处理程序. SIGUSR1交付时,将调用处理程序,它设置开关,sleep将被信号中断,您检查EINTR并立即循环检查开关,然后检查pthread_exit.

Over all this is a dubious design. With the blocked/sigpending code, depending on how long SECONDS is set to you can still wait a long time before your thread loops around to discover it is time to shutdown. If you really want to use signals for this I would suggest establishing a signal handler that sets a switch. When SIGUSR1 gets delivered the handler will be invoked, it sets the switch, sleep will be interrupted by the signal, you check for EINTR and immediately loop around to check the switch and thenpthread_exit.

选项1 (在Linux上编译)

Option 1 (compiled on 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上编译)

Option 2 (compiled on 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 如果可以的话,请使用其他机制.建议.

这篇关于Posix线程:向在while循环中运行的线程发出信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆