我试图在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倍。
下面是一些使用这种技术的代码: