【问题标题】:How to wake up a sleeping thread from the main Thread?如何从主线程唤醒休眠线程?
【发布时间】:2014-07-15 18:02:13
【问题描述】:

我有一个捕获程序,它除了捕获数据并将其写入文件还打印一些统计数据。打印统计数据的函数

static void report(void)
{
         /*Print statistics*/
}

使用每秒到期的 ALARM 大约每秒调用一次。所以程序就像

void capture_program()
{
       pthread_t report_thread

            while()
            {
                     if(pthread_create(&report_thread,NULL,report,NULL)){
                            fprintf(stderr,"Error creating reporting thread! \n");
                     }

                     /*
                        Capturing code
                        --------------
                        --------------
                      */
                      if(doreport)
                             /*wakeup the sleeping thread.*/

            }
}

void *report(void *param)
{
       //access some register from hardware
       //sleep for a second 

}

计时器到期设置doreport 标志。如果设置了此标志,则调用report() 清除该标志。

当定时器在主线程中关闭时,我如何唤醒睡眠线程(运行 report())?

【问题讨论】:

  • 您正在寻找的是某种event-signaling mechanism。将其与您的标志结合使用(并在链接文档中查找虚假唤醒以了解原因)。
  • 考虑扔掉你所拥有的,然后只使用timer_create 系列调用而不是alarm。它们允许您指定一个特定线程(或每次创建一个新线程)来将信号定向到。这正是你想要做的。否则,您必须阻止特定线程中的信号以强制它们被传递到您想要的那个,或者,或者,进入一些 condvars 之类的兔子洞。现在咬紧牙关,做正确的事。

标签: c multithreading pthreads posix


【解决方案1】:

我在编写 UDP 聊天服务器时遇到了类似的问题:有一个 thread_1 仅在警报中断(超时以查看客户端是否还活着)或另一个 thread_2(此线程满足客户端请求)信号到达时工作。我所做的是让这个 thread_1 进入睡眠状态(sleep(n*TICK_TIMER),其中 TICK_TIMER 是警报到期值,n 是某个整数 >1),然后用SIGALRM 信号唤醒这个线程。 See sleep() doc

警报处理程序(要使用它,您必须初始化它:“signal(SIGALRM, tick_handler); alarm(5);”)

void tick_handler(){tick_flag++; alarm(5); }

发生超时时将发送SIGALRM

从另一个线程_2唤醒这个睡​​眠线程_1的命令是:

    pthread_kill(X,SIGALRM);

其中 X 是 pthread_t 类型。如果你的thread_1是你的主线程,你可以通过pthread_t X = pthread_self();得到这个数字

【讨论】:

    【解决方案2】:

    您可以使用 sigwait 使线程休眠,然后使用 pthread_kill 通知该线程唤醒。 Kill 听起来很糟糕,但它不会杀死线程,它会发送一个信号。这种方法非常快。它比条件变量快得多。我不确定它更容易、更难、更安全还是更危险,但我们需要性能,所以我们走这条路。

    在某处的启动代码中:

    sigemptyset(&fSigSet);
    sigaddset(&fSigSet, SIGUSR1);
    sigaddset(&fSigSet, SIGSEGV);
    

    要休眠,线程会这样做:

    int nSig;
    sigwait(&fSigSet, &nSig);
    

    唤醒(从任何其他线程完成)

    pthread_kill(pThread, SIGUSR1);
    

    或者唤醒你可以这样做:

    tgkill(nPid, nTid, SIGUSR1);
    

    我们的代码在创建子线程之前在主线程上调用它。我不确定为什么需要这样做。

    pthread_sigmask(SIG_BLOCK, &fSigSet, NULL);
    

    【讨论】:

      【解决方案3】:

      当 定时器在主线程中关闭?

      我认为condition variable 是您正在寻找的机制。在条件变量上设置报告线程块,只要您希望报告线程唤醒,主线程就会向条件变量发出信号(更详细的说明请参见链接)。

      【讨论】:

        猜你喜欢
        • 2020-05-21
        • 2011-08-05
        • 2018-12-04
        • 1970-01-01
        • 2014-07-29
        • 1970-01-01
        • 2017-02-13
        • 2011-06-01
        • 1970-01-01
        相关资源
        最近更新 更多