Function which takes a pthread as input and suspends it

大城市里の小女人 提交于 2019-12-05 19:23:38

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 use SA_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.

johnnycrash

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!