【问题标题】:Create signal handler for a single thread为单个线程创建信号处理程序
【发布时间】:2013-12-02 10:06:53
【问题描述】:

我想知道sigaction 是否会为调用线程或整个进程创建信号处理程序。如果它解除了对信号的阻塞并为整个进程创建了一个信号处理程序,那么我怎样才能确保只有一个线程会使用该信号处理程序并让其他线程阻塞该信号。

在我的例子中,我希望一个线程在警报信号发出时调用信号处理程序,而其他线程则简单地阻止它。


void alarmSigHandler(int signo){

}

void* alarm_thread_start_routine(void *arg){

    // Perform some tasks

}


int main(){

    // Main thread start

    /* Unblock alarm signal */
    /* Assign signal handler for alarm signal */

    /* Launch alarm signal handler thread */

    /* Block alarm signal with pthread_sigmask */

    /* Do something */

    return 0;
}

http://vip.cs.utsa.edu/classes/cs3733f2013/notes/SignalsAndThreads.html

如果将信号发送到线程程序,则任何线程都可以处理该信号。

每个线程都继承进程信号掩码,但每个线程都有自己的信号掩码,可以用 pthread_sigmask 修改。

sigprocmask 不应在线程环境中使用,但可以在创建线程之前使用。

在多线程环境中处理信号的最简单方法是拥有一个专用于信号处理的线程。

涉及信号安全的问题可以使用 sigwait 来处理:

The main process blocks all signals before creating any threads.
No signal handlers are set up.
A thread is created to handle the signals.
That thread sets up a sigset_t containing the signals of interest.
It loops, calling sigwait and handles the pending signals.

【问题讨论】:

  • 为避免在处理程序设置期间出现竞争的可能性,主线程应首先忽略/阻止所有信号,然后生成线程以接收任何信号,然后是线程接收 (a) 特定信号的应设置其/他们自己需要的处理程序。

标签: c unix signals posix signal-handling


【解决方案1】:

来自man page for signals

信号处置是每个进程的属性:在多线程中 应用程序,一个特定的信号的处置是相同的 所有线程。

所以是的,当您设置信号处理程序时,它将处理发送到进程的信号;信号不会单独发送到每个线程,它会发送到任何一个没有阻止正在发送的特定消息的线程。

【讨论】:

  • 但是每个线程都可以有一个唯一的信号进程掩码不是吗?我在那个帖子中看到了这个回复:child thread inherits its parent thread's signal disposition; a thread can then alter its own disposition without affecting other threads (though any children it creates after changing the disposition inherit its then-current disposition)。这告诉我可能有一种方法让原始父线程阻塞信号,一个子线程解除阻塞并为其分配一个信号处理程序。
  • 是的,我现在明白了。但是,我认为这仅适用于与故障相关的信号(即除以零、段错误等),并且像您描述的信号将是一个进程范围的信号,将由进程上的该信号的处置来处理水平。
  • 我有另一个想法。如果主线程分配信号处理程序,启动子线程,然后主线程阻塞警报信号怎么办。我添加了一些示例代码。你是说这永远行不通吗?
  • 好问题。我不确定,但我在那个手册页中找到了这个:If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal. 我认为这意味着在你的情况下,消息将排队等待子线程执行,然后在子线程运行时调用该函数。
  • 我发现 this post 可能会有所帮助。那里的第二个答案实际上有一个来自 Linux 内核的 sn-p 代码,它被很好地注释并且可能更好地描述了消息传递将如何为您工作。
【解决方案2】:

你说:

就我而言,我希望一个线程在警报信号消失时调用信号处理程序,而其他线程则简单地阻止它。

试试这个:

void *alrm_thread(void *arg) {
  // install SIGALRM handler
  // unblock SIGALRM
  ... do stuff ...
}

int main(int argc, char **argv) {
  // block SIGALRM
  // spawn alarm_thread
  ... do stuff or spawn other threads ..
}

SIGALRM 只会传送到上面的“alrm_thread”。

更新

(正在适配Alex Che的apt cmets)

这是可行的,因为每个线程都有自己的信号掩码,该掩码继承自创建它的线程。

立即屏蔽(阻塞)main() 中的 SIGALRM,确保所有后续线程在 SIGALRM 阻塞的情况下开始生命。我们的特殊线程安装处理程序并解除阻塞 SIGALRM。由于这个特殊线程是唯一能够接收 ALRM 的线程,因此它将是运行处理程序的线程。

(现在,即将出现一些信号细微差别。处理程序或信号处置是所有线程共享的进程全局属性。信号可以是进程导向的或线程导向的。但是,对于您的情况,这是一个很常见的情况,上面是合适的。)

【讨论】:

  • 这其实是一个问题的答案(“我想要”之后的实际部分)。
  • 它有效,因为虽然整个进程的信号处置(信号处理程序)相同,但每个线程的阻塞信号掩码可能不同(并且从父线程继承)。因此,如果我们仅在一个线程中解除阻塞信号,则安装的进程信号处理程序将仅在该线程中被调用。
猜你喜欢
  • 2023-02-19
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 2015-09-16
  • 2012-01-24
  • 2011-11-18
  • 1970-01-01
相关资源
最近更新 更多