2

非常に単純なスレッドがあります。キープアライブパケットをサーバーに送信してからスリープします。メインスレッドがスレッドに終了するよう通知したいのですが、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() を使用する必要がありますか?

4

2 に答える 2

5

OS によって配信されたが、プロセスまたはスレッドによってブロックされている場合、シグナルは保留中です。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 可能であれば、他のメカニズムを使用します。アドバイスした。

于 2013-07-12T03:44:16.010 に答える
2

シグナルを失い、代わりに pthread 条件変数を使用します。たとえば、pthread_cond_timedwait()):

私見では...

于 2013-07-12T03:18:52.170 に答える