Function which takes a pthread as input and suspends it
I'm trying to port the real time Thread_Metric from ExpressLogic in POSIX, in order to benchmark PREEMPT_RT patches for Linux, Xenomai and RTAI for my thesis. They provide a C source file with the following functions, which you have to implement in order for the benchmark to work:
void tm_initialize(void (*test_initialization_function)(void));
int tm_thr开发者_开发技巧ead_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);
Right now I'm trying to implement the tm_thread_suspend and tm_thread_resume functions, which take a pthread as input. I know that you can suspend a pthread with pthread_mutex_lock and pthread_cond_wait routines, but you have to call these from the thread start_function. I'm new at this kind of stuff and I'm way in over my head. Any help is appreciated.
pthread_suspend
really seems the way to go if it's available. This solution might be more dirty than it's worth. For each thread keep a semaphore
. Make each thread listen for signals. In the signal handler simply do a down
on the associated semaphore.
So when you want to stop
a thread, simply send it a signal (perhaps using a real-time signal would be best) and it will stop in the handler. The handler masks itself by default (that is, it won't be called again if the same signal is received before it is done). When you want to restart the thread, simply do an up
on the semaphore.
Caveat:
- Use what @bmargulies suggested, it's better (safer, cleaner, more efficient) if you can
- You can also use a mutex instead of a semaphore
- Dealing with signals is a nasty job. Before embarking make sure you (re)read about
- async-signal-safety
- threads and signals
- interrupting and restarting system calls (
SA_RESTART
)
- I am pretty sure
sem_wait(3)
isn't async-signal safe, but it's safe as long as you don't useSA_NODEFER
(not that you'd have any reason)
Unfortunately I can't find any really stellar free documentation about this. Still, stellar or not, there is a lot of free documentation.
Edit
As suggested by @R.. there are async-signal-safe
functions that block that you could use (instead of the unsafe sem_wait
). Here's a list of functions you may safely use.
You can do this completely portably (avoiding all issues with async-signal-unsafe functions) using two signals:
The "thread suspend" signal handler would use pselect
to atomically unblock the second signal and sleep indefinitely. The second signal would terminate the pselect
and cause the signal handler to return.
Also there are plenty of other solutions using async-signal-safe interfaces - basically anything that deals with file descriptors and blocking on them rather than on user-space synchronization primitives. For example, having the signal handler read
from a pipe and writing a single byte to the pipe to resume the thread would work.
Some implementations of pthreads have these functions. http://www.unix.com/man-page/all/3t/pthread_suspend/ But your linux kernel may not support them.
The way you do this is to use sigwait() and pthread_kill.
// global variable
int _fSigSet;
Before calling pthread_create we set a signal mask. Every thread will inherit the mask. You could set the mask in the thread function I suppose. Here is the code we use:
sigemptyset(&_fSigSet);
sigaddset(&_fSigSet, SIGUSR1);
sigaddset(&_fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &_fSigSet, NULL);
...
pthread_create(&Thread, NULL, ThreadProc, NULL);
...
To SUSPEND:
int nSig; // signal you get if you care.
sigwait(&_fSigSet, &nSig); // thread is suspended here waiting for signal.
To RESUME:
pthread_kill(&Thread, SIGUSR1);
If you cant use SIGUSR1 for some reason be aware that not all signals work for us. We may be doing something wrong, but SIGCONT doesn't work.
We have benchmarked pausing threads this way and this method was 5x faster than using mutexes and condition variables.
Here is some code that uses this technique.
精彩评论