【问题标题】:Function which takes a pthread as input and suspends it将 pthread 作为输入并将其挂起的函数
【发布时间】:2011-08-09 21:04:02
【问题描述】:

我正在尝试在 POSIX 中从 ExpressLogic 移植实时 Thread_Metric,以便为我的论文对 Linux、Xenomai 和 RTAI 的 PREEMPT_RT 补丁进行基准测试。它们提供了具有以下功能的 C 源文件,您必须实现这些功能才能使基准测试工作:

void   tm_initialize(void (*test_initialization_function)(void));
int    tm_thread_create(int thread_id, int priority, void (*entry_function)(void));
int    tm_thread_resume(int thread_id);
int    tm_thread_suspend(int thread_id);
void   tm_thread_relinquish(void);
void   tm_thread_sleep(int seconds);
int    tm_queue_create(int queue_id);
int    tm_queue_send(int queue_id, unsigned long *message_ptr);
int    tm_queue_receive(int queue_id, unsigned long *message_ptr);
int    tm_semaphore_create(int semaphore_id);
int    tm_semaphore_get(int semaphore_id);
int    tm_semaphore_put(int semaphore_id);
int    tm_memory_pool_create(int pool_id);
int    tm_memory_pool_allocate(int pool_id, unsigned char **memory_ptr);
int    tm_memory_pool_deallocate(int pool_id, unsigned char *memory_ptr);

现在我正在尝试实现 tm_thread_suspend 和 tm_thread_resume 函数,它们将 pthread 作为输入。我知道您可以使用 pthread_mutex_lock 和 pthread_cond_wait 例程挂起 pthread,但您必须从线程 start_function 调用它们。我是这种东西的新手,而且我已经过头了。任何帮助表示赞赏。

【问题讨论】:

    标签: c pthreads real-time xenomai preempt-rt


    【解决方案1】:

    pthread_suspend 如果可用的话,确实是可行的方法。这个解决方案可能比它的价值更脏。为每个线程保留一个semaphore。让每个线程监听信号。在信号处理程序中,只需对关联的信号量执行 down

    因此,当您想stop 一个线程时,只需向它发送一个信号(也许使用实时信号最好),它就会在处理程序中停止。默认情况下,处理程序会屏蔽自身(也就是说,如果在完成之前接收到相同的信号,则不会再次调用它)。当您想重新启动线程时,只需在信号量上执行up

    警告:

    • 使用@bmargulies 的建议,如果可以的话会更好(更安全、更清洁、更高效)
    • 您也可以使用互斥锁代替信号量
    • 处理信号是一项令人讨厌的工作。在开始之前,请确保您(重新)阅读
      • 异步信号安全
      • 线程和信号
      • 中断和重新启动系统调用 (SA_RESTART)
    • 我很确定 sem_wait(3) 不是异步信号安全的,但只要你不使用SA_NODEFER(不是你会有任何理由)

    不幸的是,我找不到任何关于此的真正出色的免费文档。尽管如此,无论是否出色,仍有大量免费文档。

    编辑

    正如@R.. 所建议的,有async-signal-safe 函数可以阻止您使用(而不是不安全的sem_wait)。这是a list of functions you may safely use

    【讨论】:

    • 您有正确的方法,但需要信号处理程序中的异步信号安全功能。我的回答勾勒出了一些想法。
    • @R.. 这是个好主意。我可以看到SUSv3pselect(2) 指定为异步信号安全,这将解决这种方法的问题。
    【解决方案2】:

    您可以使用两个信号完全可移植地执行此操作(避免异步信号不安全函数的所有问题):

    “线程挂起”信号处理程序将使用pselect 自动解除对第二个信号的阻塞并无限期休眠。第二个信号将终止pselect 并导致信号处理程序返回。

    还有很多其他使用异步信号安全接口的解决方案——基本上是处理文件描述符并阻止它们而不是用户空间同步原语的任何解决方案。例如,让来自管道的信号处理程序read 并将单个字节写入管道以恢复线程将起作用。

    【讨论】:

      【解决方案3】:

      pthread 的一些实现具有这些功能。 http://www.unix.com/man-page/all/3t/pthread_suspend/ 但是你的 linux 内核可能不支持它们。

      【讨论】:

      • pthread_suspend 不是 pthread 函数,它是一些供应商扩展。
      • 'pthread_suspend() 和 pthread_continue() 是由 X/Open 开发的。'
      • 尚未包含在标准中。您可能可以挖掘基本原理文档并找到一个很好的理由。
      【解决方案4】:

      执行此操作的方法是使用 sigwait() 和 pthread_kill。

      // 全局变量

      int _fSigSet; 
      

      在调用 pthread_create 之前,我们设置了一个信号掩码。每个线程都将继承掩码。你可以在我想的线程函数中设置掩码。这是我们使用的代码:

      sigemptyset(&_fSigSet);
      sigaddset(&_fSigSet, SIGUSR1);
      sigaddset(&_fSigSet, SIGSEGV);
      pthread_sigmask(SIG_BLOCK, &_fSigSet, NULL);
      ... 
      pthread_create(&Thread, NULL, ThreadProc, NULL);
      ...
      

      暂停:

      int nSig;  // signal you get if you care.
      sigwait(&_fSigSet, &nSig);  // thread is suspended here waiting for signal.
      

      恢复:

      pthread_kill(&Thread, SIGUSR1);
      

      如果您由于某种原因不能使用 SIGUSR1,请注意并非所有信号都对我们有效。我们可能做错了什么,但 SIGCONT 不起作用。

      我们以这种方式对暂停线程进行了基准测试,这种方法比使用互斥锁和条件变量快 5 倍。

      这里有一些使用这种技术的code

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-02
        相关资源
        最近更新 更多