Вопрос: sigwait () и обработчик сигналов


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

Итак, какой из них будет обработан первым? Обработчик сигналов или 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 () и обработчика сигнала.


6


источник


Ответы:


Из 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;
}

3



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

В нем говорится:

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

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


2



Я знаю, что этот вопрос около года, но я часто использую шаблон, который решает именно эту проблему с использованием 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;
}

1



Из фрагмента кода, который вы опубликовали, кажется, что вы используете 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