【问题标题】:What are the pitfalls of using `pause()` in signal handler?在信号处理程序中使用 `pause()` 的陷阱是什么?
【发布时间】:2019-06-20 11:51:29
【问题描述】:

我想暂停线程并恢复它。列出的方法很少here。但是我想到了使用unistd.h中的pause()库函数。

在信号处理程序中使用暂停有哪些陷阱?

我注意到,当我发送 0 以暂停线程并再次发送 0 时,我的信号已排队。我需要发送1 两次才能恢复线程。

我想这样的情况可能还有很多。如果我想在信号处理程序中使用pause()sleep(),如何处理这种情况。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>

static bool thread_ready = false;

static void cb_sig(int signal)
{
        if (signal == SIGUSR1)
                pause();
        else if (signal == SIGUSR2)
                ;
}

static void *thread_job(void *ignore)
{
        int i = 0;
        struct sigaction act;

        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = cb_sig;

        if (sigaction(SIGUSR1, &act, NULL) == -1)
                printf("unable to handle siguser1\n");
        if (sigaction(SIGUSR2, &act, NULL) == -1)
                printf("unable to handle siguser2\n");

        thread_ready = true;
        while (1) {
                printf("thread counter: %d\n", i++);
                sleep(1);
        }

        return NULL;
}

int main()
{
        bool running;
        int user_input;
        pthread_t thread;

        if (pthread_create(&thread, NULL, thread_job, NULL))
                return -1;

        while (!thread_ready);

        for (running = true; running; ) {
                printf("0: pause thread, 1: resume thread, -1: exit\n");
                scanf("%d", &user_input);

                switch(user_input) {
                case -1:
                        running = false;
                        break;
                case 0:
                        pthread_kill(thread, SIGUSR1);
                        break;
                case 1:
                        pthread_kill(thread, SIGUSR2);
                        break;
                }
        }

        pthread_kill(thread, SIGKILL);
        return 0;
}

【问题讨论】:

  • 为什么要在信号处理程序中使用pause()sleep()?而不是使用信号,为什么你的main() 函数不直接挂起或暂停线程?一般来说,终止线程是有问题的 - 通常最好将信息发送给导致它干净地结束的线程,而不是试图直接杀死它。
  • 对不起,我忘了提我的用例,考虑一个线程池,所以一个作业将被传递给一个线程。现在,线程正在执行一项工作,我希望我的线程池具有暂停/恢复功能。所以线程应该挂起,即使它在工作的中间。会有一个监控线程负责暂停和恢复池中的其他线程。
  • 如果一个程序中的一个线程挂起另一个线程,即使在“工作中间”它也会被挂起。当它恢复时,它将从暂停的地方继续。不需要信号。
  • 是它应该恢复它的工作,即在它被暂停的地方恢复

标签: c pthreads signal-handling


【解决方案1】:

信号处理程序不应该sleep(),也可能不应该pause(),尽管从技术上讲,这两个函数都是异步信号安全的。信号处理程序应该快速运行并最小化或(最好)完全避免阻塞。

至于具体的陷阱,您已经注意到一个:默认情况下,信号在其处理程序运行时会自动被阻塞。可以以一种避免这种情况的方式安装处理程序,但这对您没有帮助:如果您一直发送由您的特定处理程序处理的信号,那么您将始终在该处理程序中阻塞至少一个线程。如果您一直将它们发送到同一个线程,那么该线程将永远不会解除阻塞。

更一般地说,信号掩码、信令和信号接收阻塞的信号处理程序之间可能会发生任何数量的不良交互。

此外,pause() 相当不具体,除非您将其与设置相当严格的信号掩码结合使用(在这种情况下,sigsuspend() 可能是更好的选择)。但是,如果您设置了限制性信号掩码,则可能会干扰信号的其他用途。

除了避免在信号处理程序中使用pause()sleep() 之外,不要“处理”此类问题。

【讨论】:

  • 如果我可以将信号处理程序与中断联系起来,信号处理程序应该很短并立即返回,对吗?所以,我需要推迟处理。
  • @Shubham 中断服务例程绝对应该尽可能短且快速。通常,它们用于简单地设置标志并返回;程序的另一部分将作用于该设置标志。
猜你喜欢
  • 2018-08-09
  • 2017-11-13
  • 2015-01-20
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 2012-04-06
相关资源
最近更新 更多