2014-02-04 2 views
4

Если я настроил и обработчик сигналов для SIGABRT, и между тем у меня есть поток, который ждет sigwait() для SIGABRT (я заблокировал SIGABRT в других потоках pthread_sigmask).sigwait() и обработчик сигналов

Итак, какой из них будет обработан первым? Обработчик сигналов или sigwait()?

[У меня возникли проблемы с тем, что sigwait() блокируется навсегда. Я ее отладки в настоящее время]

main() 
{ 
    sigset_t     signal_set; 

    sigemptyset(&signal_set); 
    sigaddset(&signal_set, SIGABRT); 
    sigprocmask(SIG_BLOCK, &signal_set, NULL); 

    // Dont deliver SIGABORT while running this thread and it's kids. 
    pthread_sigmask(SIG_BLOCK, &signal_set, NULL); 

    pthread_create(&tAbortWaitThread, NULL, WaitForAbortThread, NULL); 
    .. 
    Create all other threads 
    ... 
} 

static void* WaitForAbortThread(void* v) 
{ 
    sigset_t signal_set; 
    int stat; 
    int sig; 

    sigfillset(&signal_set); 
    pthread_sigmask(SIG_BLOCK, &signal_set, NULL); // Dont want any signals 


    sigemptyset(&signal_set); 
    sigaddset(&signal_set, SIGABRT);  // Add only SIGABRT 

    // This thread while executing , will handle the SIGABORT signal via signal handler. 
    pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 
    stat= sigwait(&signal_set, &sig ); // lets wait for signal handled in CatchAbort(). 
    while (stat == -1) 
    { 
     stat= sigwait(&signal_set, &sig ); 
    } 

    TellAllThreadsWeAreGoingDown(); 

    sleep(10); 

    return null; 
} 

// Abort signal handler executed via sigaction(). 
static void CatchAbort(int i, siginfo_t* info, void* v) 
{ 
    sleep(20); // Dont return , hold on till the other threads are down. 
} 

Здесь на sigwait(), я познаю, что SIGABRT получено. Об этом расскажу другие темы. Затем будет удерживать обработчик сигнала прерывания, чтобы процесс не был завершен.

Я хотел знать взаимодействие sigwait() и обработчика сигнала.

+0

Как установить обработчик для 'SIGABRT'? Он будет вызываться только при отправке сигнала. Как отправляется «SIGABRT»? Прочитайте [сигнал (7)] (http://man7.org/linux/man-pages/man7/signal.7.html) Обратите внимание, что [abort (3)] (http://man7.org/linux/man -pages/man3/abort.3.html), вероятно, отправляет его в отправляющий поток. –

+0

Разум, размещающий некоторый код? Что вы ожидаете от sigwait()? –

+0

abort() API используется для отправки SIGABRT при незаконном параметре или неправильных операциях. Он может быть отправлен из любого из потоков в программе. –

ответ

0

Из фрагмента кода, который вы опубликовали, похоже, что вы используете sigwait() неправильно. AFAIU, вам нужно WaitForAbortThread, как показано ниже:

 sigemptyset(&signal_set); // change it from sigfillset() 
    for (;;) { 
      stat = sigwait(&signal_set, &sig); 

      if (sig == SIGABRT) { 
      printf("here's sigbart.. do whatever you want.\n"); 
      pthread_kill(tid, signal); // thread id and signal 
     } 
     } 

Я не думаю, что pthread_sigmask() действительно необходимо. Поскольку вы только хотите обрабатывать SIGABRT, сначала инициализируйте signal_set как пустой, просто добавьте SIGABRT, а затем перейдите в бесконечный цикл, sigwait будет ждать определенного сигнала, который вы ищете, вы проверяете сигнал, если это SIGABRT, если да - делай что хочешь. Обратите внимание на использование pthread_kill(), используйте его для отправки любого сигнала в другие потоки, указанные через tid, и сигнал, который вы хотите отправить, убедитесь, что вы знаете, что есть другие потоки, которые вы хотите передать. Надеюсь, это поможет!

+0

Моя идея состояла в том, чтобы блокировать SIGABRT во всех других потоках. Поэтому я маскировал SIG_BLOCK в main(), и, таким образом, дочерние потоки также не получат его. Мне нужно разблокировать его в WaitForAbortThread() для его получения. Поскольку ни один другой поток не может получать SIGABRT, WaitForAbortThread() является единственным потоком, который мог бы его получить. Проблема, с которой я столкнулся, - sigwait() заблокирована навсегда (даже если один из других потоков вызывает abort(), который отправляет SIGABRT)!. Между тем, если я устанавливаю обработчик сигнала, используя sigaction(), этот обработчик вводится. –

+1

Если вы хотите, чтобы sigwait() выполнял какую-либо другую вещь, то избегайте цикла, но это так, как обычно используется sigwait(), и этот метод является особенно полезным для обработки нескольких сигналов, в противном случае простая обработка сигналов должна быть достаточной. –

1

Я получил некоторую информацию из этого < link>

Он говорит:

Чтобы поток ждать асинхронно генерируемых сигналов, библиотека потоков обеспечивает подпрограмму sigwait. Подпрограмма sigwait блокирует вызывающий поток, пока один из ожидаемых сигналов не будет отправлен процессу или потоку. На ожидаемом сигнале не должно быть обработчика сигналов с помощью подпрограммы sigwait.

Я удалю обработчик sigaction() и попробую только sigwait().

2

Из sigwait() документации:

sigwait() функция приостанавливает выполнение вызывающего потока до одного из сигналов, указанных в наборе сигнала переходит в режим ожидания.

Ожидающий сигнал означает сигнал блокировки, ожидающий доставки в один из потоков/процессов. Поэтому вам нужно не, чтобы разблокировать сигнал, как вы это делали, с вашим звонком pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL).

Это должно работать:

static void* WaitForAbortThread(void* v){ 
    sigset_t signal_set; 

    sigemptyset(&signal_set); 
    sigaddset(&signal_set, SIGABRT); 

    sigwait(&signal_set, &sig ); 

    TellAllThreadsWeAreGoingDown(); 

    sleep(10); 

    return null; 
} 
1

Я знаю, что этот вопрос примерно год назад, но я часто использую шаблон, который решает именно эту проблему, используя Pthreads и сигналы. Это небольшая длина, но я забочусь о любых проблемах, о которых я знаю.

Недавно я использовал его в сочетании с библиотекой, обернутой SWIG и вызываемой из Python. Досадная проблема заключалась в том, что поток IRQ, ожидающий SIGINT с использованием sigwait, никогда не получал сигнал SIGINT. Одна и та же библиотека отлично работала при вызове из Matlab, который не записывал сигнал SIGINT.

Решение было установить обработчик сигнала

#define _NTHREADS 8 

#include <signal.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <sched.h> 
#include <linux/unistd.h> 
#include <sys/signal.h> 
#include <sys/syscall.h> 
#include <setjmp.h> 

#include <stdio.h> 
#include <stdlib.h> 

#include <errno.h> 
#include <string.h> // strerror 

#define CallErr(fun, arg) { if ((fun arg)<0)   \ 
     FailErr(#fun) } 

#define CallErrExit(fun, arg, ret) { if ((fun arg)<0) \ 
     FailErrExit(#fun,ret) } 

#define FailErrExit(msg,ret) {     \ 
    (void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \ 
     msg, errno, strerror(errno));    \ 
    (void)fflush(stderr);      \ 
    return ret; } 

#define FailErr(msg) {          \ 
    (void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \ 
     msg, errno, strerror(errno));    \ 
    (void)fflush(stderr);} 

typedef struct thread_arg { 
    int cpu_id; 
    int thread_id; 
} thread_arg_t; 

static jmp_buf jmp_env; 

static struct sigaction act; 
static struct sigaction oact; 

size_t exitnow = 0; 
pthread_mutex_t exit_mutex; 

pthread_attr_t attr; 

pthread_t pids[_NTHREADS]; 
pid_t  tids[_NTHREADS+1]; 

static volatile int status[_NTHREADS]; // 0: suspended, 1: interrupted, 2: success 

sigset_t mask; 

static pid_t gettid(void); 
static void *thread_function(void *arg); 
static void signalHandler(int); 

int main() { 

    cpu_set_t cpuset; 
    int nproc; 
    int i; 
    thread_arg_t thread_args[_NTHREADS]; 
    int id; 

    CPU_ZERO(&cpuset); 
    CallErr(sched_getaffinity, 
     (gettid(), sizeof(cpu_set_t), &cpuset)); 

    nproc = CPU_COUNT(&cpuset); 

    for (i=0 ; i < _NTHREADS ; i++) { 
    thread_args[i].cpu_id = i % nproc; 
    thread_args[i].thread_id = i; 
    status[i] = 0; 
    } 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 

    pthread_mutex_init(&exit_mutex, NULL); 

    // We pray for no locks on buffers and setbuf will work, if not we 
    // need to use filelock() on on FILE* access, tricky 

    setbuf(stdout, NULL); 
    setbuf(stderr, NULL); 

    act.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; 
    act.sa_handler = signalHandler; 
    sigemptyset(&act.sa_mask); 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGINT); 

    if (setjmp(jmp_env)) { 

    if (gettid()==tids[0]) { 
     // Main Thread 
     printf("main thread: waiting for clients to terminate\n"); 
     for (i = 0; i < _NTHREADS; i++) { 
    CallErr(pthread_join, (pids[i], NULL)); 
    if (status[i] == 1) 
     printf("thread %d: terminated\n",i+1); 
     } 
     // On linux this can be done immediate after creation 
     CallErr(pthread_attr_destroy, (&attr)); 
     CallErr(pthread_mutex_destroy, (&exit_mutex)); 

     return 0; 
    } 
    else { 
     // Should never happen 
     printf("worker thread received signal"); 
    } 
    return -1; 
    } 

    // Install handler 
    CallErr(sigaction, (SIGINT, &act, &oact)); 

    // Block SIGINT 
    CallErr(pthread_sigmask, (SIG_BLOCK, &mask, NULL)); 

    tids[0] = gettid(); 
    srand (time(NULL)); 

    for (i = 0; i < _NTHREADS; i++) { 
    // Inherits main threads signal handler, they are blocking 
    CallErr(pthread_create, 
     (&pids[i], &attr, thread_function, 
     (void *)&thread_args[i])); 
    } 

    if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) { 
    fprintf(stderr, "main thread: can't block SIGINT"); 
    } 
    printf("Infinite loop started - CTRL-C to exit\n"); 

    for (i = 0; i < _NTHREADS; i++) { 
    CallErr(pthread_join, (pids[i], NULL)); 
    //printf("%d\n",status[i]); 
    if (status[i] == 2) 
     printf("thread %d: finished succesfully\n",i+1); 
    } 

    // Clean up and exit 
    CallErr(pthread_attr_destroy, (&attr)); 
    CallErr(pthread_mutex_destroy, (&exit_mutex)); 

    return 0; 

} 

static void signalHandler(int sig) { 

    int i; 
    pthread_t id; 

    id = pthread_self(); 

    for (i = 0; i < _NTHREADS; i++) 
    if (pids[i] == id) { 
     // Exits if worker thread 
     printf("Worker thread caught signal"); 
     break; 
    } 

    if (sig==2) { 
    sigaction(SIGINT, &oact, &act); 
    } 

    pthread_mutex_lock(&exit_mutex); 
    if (!exitnow) 
    exitnow = 1; 
    pthread_mutex_unlock(&exit_mutex); 

    longjmp(jmp_env, 1); 
} 

void *thread_function(void *arg) { 
    cpu_set_t set; 

    thread_arg_t* threadarg; 

    int thread_id; 

    threadarg = (thread_arg_t*) arg; 

    thread_id = threadarg->thread_id+1; 

    tids[thread_id] = gettid(); 

    CPU_ZERO(&set); 
    CPU_SET(threadarg->cpu_id, &set); 

    CallErrExit(sched_setaffinity, (gettid(), sizeof(cpu_set_t), &set), 
      NULL); 

    int k = 8; 
    // While loop waiting for exit condition 
    while (k>0) { 
    sleep(rand() % 3); 
    pthread_mutex_lock(&exit_mutex); 
    if (exitnow) { 
     status[threadarg->thread_id] = 1; 
     pthread_mutex_unlock(&exit_mutex); 
     pthread_exit(NULL); 
    } 
    pthread_mutex_unlock(&exit_mutex); 
    k--; 
    } 

    status[threadarg->thread_id] = 2; 
    pthread_exit(NULL); 
} 

static pid_t gettid(void) { 
    pid_t pid; 
    CallErr(pid = syscall, (__NR_gettid)); 
    return pid; 
} 
Смежные вопросы