简体   繁体   English

在多线程进程中处理信号的示例

[英]Example of handling signals in multi-threaded process

Can anyone give me the steps or even the code for the following situation: 任何人都可以给我以下情况的步骤甚至代码:

A process which contains multiple thread, and of these threads is responsible of catching a user defined signal SIGUSR1. 包含多个线程的进程以及这些线程负责捕获用户定义的信号SIGUSR1。 Only this thread should be capable of receiving this signal, and upon the reception of this signal I do some stuff. 只有这个线程应该能够接收到这个信号,并且在接收到这个信号后我会做一些事情。

In my situation the signal is being sent by a Kernel Module to my Process ID. 在我的情况下,内核模块将信号发送到我的进程ID。 Then it is the responsibility of my process to deliver it to the correct listening thread, which has also established the Signal Handler ie the signal handler is not in the main thread. 然后我的过程负责将它传递给正确的监听线程,该线程还建立了信号处理程序,即信号处理程序不在主线程中。

I already did some code which runs for a single-thread process, but I have a problem in running it in multiple thread environment. 我已经为一个单线程进程运行了一些代码,但是在多线程环境中运行它时遇到了问题。

I am running my code on Linux Ubuntu 12.04.3 with Kernel Version 3.8.0-29. 我在Linux Ubuntu 12.04.3上使用内核版本3.8.0-29运行我的代码。 And for the creation of the process I am mixing between Boost Threads and POSIX threads API. 为了创建流程,我将在Boost Threads和POSIX threads API之间进行混合。

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>

/* Value of the last signal caught */
volatile sig_atomic_t sig_value;

static void sig_handler(const int sig_number, siginfo_t *sig_info, void *context)
{
if (sig_number == SIGSEGV)
{
    error_sys("Error at address 0x%lx", (long)sig_info->si_addr);
    exit(-1);
}
sig_value = sig_number;
}


int init_signal_catcher()
{
struct sigaction sig_action; /* Structure describing the action to be taken when asignal arrives.  */

sigset_t oldmask;  /* Signal mask before signal disposition change.      */
sigset_t newmask;  /* Signal mask after signal disposition change.       */
sigset_t zeromask; /* Signal mask to unblock all signal while suspended. */

/* Define signal mask and install signal handlers */
memset(&sig_action, 0, sizeof(struct sigaction));

sig_action.sa_flags = SA_SIGINFO;
sig_action.sa_sigaction = sig_handler;

/* Examine and change a signal action. */
sigaction(SIGHUP, &sig_action, NULL);
sigaction(SIGINT, &sig_action, NULL);
sigaction(SIGTERM, &sig_action, NULL);
sigaction(SIGSEGV, &sig_action, NULL);
sigaction(SIGUSR1, &sig_action, NULL);

    /* Block SIGHUP, SIGINT, SIGTERM, SIGSEGV and SIGUSR1 signals. */
sigemptyset(&newmask);
sigaddset(&newmask, SIGHUP);
sigaddset(&newmask, SIGINT);
sigaddset(&newmask, SIGTERM);
sigaddset(&newmask, SIGSEGV);
sigaddset(&newmask, SIGUSR1);

/* Examine and change blocked signals. */
pthread_sigmask(SIG_BLOCK, &newmask, &oldmask);

/* Initialize the empty signal set. */
sigemptyset(&zeromask);
sig_value = 0;

while ((sig_value != SIGINT) && (sig_value != SIGTERM))
{
    sig_value = 0;

    /*
     * Go to sleep (unblocking all signals) until a signal is catched.
     * On return from sleep, the signals SIGHUP, SIGINT, SIGTERM and
         * SIGUSR1 are again blocked.
     */
        printf("Suspending on %lu mask.", zeromask);

        // Wait for a signal.
    sigsuspend(&zeromask);

    switch(sig_value)
    {
                printf("Caught Signal %d", sig_value);
        case SIGUSR1:
                    printf("Caught SIGUSR1");
                    break;
    }
}

return 0;
}

The signals need to be blocked in every thread. 需要在每个线程中阻止信号。 The safest way to do this is to block them in the first thread before any others are created. 最安全的方法是在创建任何其他线程之前在第一个线程中阻止它们。 Then a single, specially chosen thread can call sigsuspend() and only that thread will execute the signal handlers. 然后,一个特别选择的线程可以调用sigsuspend() ,只有该线程才能执行信号处理程序。

void *signal_handling_thread(void *whatever) {
  sig_value := 0
  while (sig_value not in (SIGTERM, SIGINT)) {
    sigsuspend(empty_mask)
    ...
  }
  ...
}

int main(int argc, char **argv) {
  block_relevant_signals();               // SIG_BLOCK HUP, TERM, USR1, etc.
  catch_relevant_signals();               // SA_SIGINFO ...

  spawn_signal_handling_thread();         // spawned with relevant signals blocked

  for (int i = 0; i < NUM_WORKERS; i++) {
    spawn_worker_thread();                // spawned with relevant signals blocked
  }
  ...
}

It's time to refactor your code to break apart concerns — do global process attribute manipulation in one place, signal-specific reaction in another, etc. 是时候重构你的代码来分解问题了 - 在一个地方进行全局流程属性操作,在另一个地方进行信号特定反应,等等。

In your signal handler, you are calling exit(-1). 在信号处理程序中,您正在调用exit(-1)。 exit(-1) is not asynchronous signal-handler safe. exit(-1)不是异步信号处理程序安全的。 Use _exit(-1) instead. 请改用_exit(-1)。

The difference between the two functions is that exit() calls all of the registered atexit() routines (including C++ static destructors). 这两个函数之间的区别在于exit()调用所有已注册的atexit()例程(包括C ++静态析构函数)。 Before exit() does that shutdown step, it uses pthread_mutex_lock() to ensure a thread-safe shutdown. 在exit()执行该关闭步骤之前,它使用pthread_mutex_lock()来确保线程安全关闭。 If the lock happens to be held by another thread, your program will deadlock. 如果锁定恰好由另一个线程持有,那么您的程序将会死锁。

_exit() skips those atexit routines and terminates the process. _exit()跳过那些atexit例程并终止进程。

I'm not familiar with error_sys(), but it looks like it ends up using printf()/fprintf(). 我不熟悉error_sys(),但看起来它最终使用printf()/ fprintf()。 Those routines also tend to be protected by mutexes. 这些例程也往往受到互斥体的保护。

下面是一个使用pthread_sigmask组织哪个线程获取哪个信号的示例: http//man7.org/linux/man-pages/man3/pthread_sigmask.3.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM