函数接受一个pthread作为输入并挂起它



我试图在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调用这些例程。我是这种事的新手,我完全搞不懂。

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

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

注意:

  • 使用@bmargulies的建议,如果您可以
  • ,它会更好(更安全,更清洁,更高效)
  • 你也可以用互斥来代替信号量
  • 处理信号是一项棘手的工作。在登船之前,确保你读过
    • async-signal-safety
    • 线程和信号
    • 中断和重启系统调用(SA_RESTART)
  • 我很确定 sem_wait(3) 不是异步信号安全,但它是安全的,只要你不使用SA_NODEFER (不是你有任何理由)

不幸的是,我找不到任何关于这个的真正优秀的免费文档。不过,不管是不是一流的,还是有很多免费的文档。

编辑

根据@R的建议…您可以使用async-signal-safe函数阻塞(而不是不安全的sem_wait)。下面是你可以安全使用的函数列表

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

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

还有很多其他使用异步信号安全接口的解决方案——基本上是任何处理文件描述符和阻塞的方法,而不是处理用户空间同步原语。例如,在管道中使用信号处理程序read并向管道中写入单个字节以恢复线程是可行的。

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

可以使用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倍。

下面是一些使用这种技术的代码:

最新更新