Suspend pthreads without using condition
Asked Answered
P

7

7

I want to suspend pthreads but apparently, there is no such function as pthread_suspend. I read somewhere about suspending pthreads using mutexes and conditions and used it as following:

#include <pthread.h>

class PThread {
public:
pthread_t myPthread;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;

void start() {
pthread_create(&myPthread, NULL, threadRun, (void*)this );
}

Thread() { }

void suspendMe() {
pthread_cond_wait(&m_ResumeCond,&m_SuspendMutex);
}

void resume() {
pthread_cond_signal(&m_ResumeCond);
}
};

but I don't understand why we need both mutex and condition to suspend and resume a pthread. Is it possible to suspend and resume it without using conditions?

Pricilla answered 29/6, 2010 at 13:5 Comment(0)
S
9

Your code is not correct - the pthread_cond_wait() requires that the mutex be locked already when you call it:

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

However, this is still wrong. A thread can wake up from pthread_cond_wait() at any time, not necessarily only when it is signalled. This means that you need to pair pthread_cond_wait() with some shared state that encodes the condition that the thread is really waiting for - in the simplest case, you can just use a flag variable. pthread_cond_signal() is used to tell the thread that it should wake and re-check the shared state. Applying this to your implementation:

class PThread {
    public:

    pthread_t myPthread;
    bool suspended;
    pthread_mutex_t m_SuspendMutex;
    pthread_cond_t m_ResumeCond;

    void start() {
        suspended = false;
        pthread_create(&myPthread, NULL, threadRun, (void*)this );
    }

    Thread() { }

    void suspendMe() {
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = true;
        do {
            pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
        } while (suspended);
        pthread_mutex_unlock(&m_SuspendMutex);
    }

    void resume() {
        /* The shared state 'suspended' must be updated with the mutex held. */
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = false;
        pthread_cond_signal(&m_ResumeCond);
        pthread_mutex_unlock(&m_SuspendMutex);
    }
};

The reason the mutex is provided is to protect the shared state and avoid race conditions - the pthread_cond_wait() function actually performs an atomic-unlock-and-wait when it waits, which allows a "missed wakeup" to be avoided. For example in this code, the mutex prevents suspended from changing to false in between the suspended = true; and pthread_cond_wait() lines.

Snapback answered 29/6, 2010 at 13:41 Comment(5)
Also, you are required to check your condition after wakeup because the system may wake your thread up with the condition false! For example, the system may have woken 10 threads and one of them already finished the job.Karwan
@Zan Lynx: Aye, POSIX is quite clear on this point: "Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur." (although I believe the Linux implementation does not do spurious wakeups).Snapback
So pthread_cond_wait is like a really loose dogchain. Your pitbull could go and start biting neighbours any minute.Ethiopian
No, it's more like the bell on the counter at a shop. If you ring it, the shopkeeper will definitely come to the counter and ask what you want, but if you don't ring it they might come anyway.Snapback
Wonder about the use case of "suspend()". when the thread is already running.Ursine
L
5

If a thread wasn't waiting on some condition or other, how could you "signal" it to resume. It can't just stop executing anything at all and then magically start again, so it waits on a condition.

To elaborate, in pthreads, the way to resume a thread is in fact to use condition variables. There isn't an API available to suspend/resume a thread in any other way. Waiting on pthread_cond_wait is cheap, it blocks until the condition is signaled, not using (much?) CPU. You use the condition to signal the thread to wake up, and the mutex is required to protect access to the condition variable and the code in the thread upon wakeup.

Lilywhite answered 29/6, 2010 at 13:26 Comment(5)
"how could you "signal" it to resume?" It's possible in other API's! For example, ResumeThread in the Windows API works by accepting an integer thread id. There is also a SuspendThread function. Together you can easily wake up or suspend worker threads (from the main thread) in a threadpool as work becomes available or gets finished.Ethiopian
There is a nice paragraph here which describes this same thing.Ethiopian
@Ethiopian did you read the documentation for those functions? They are not for thread synchronization, but for debuggers. pthreads is a library supplying threading functionality, including synchronization. It is not a library for implementing debuggers, and therefore it doesn't have an equivalent of functions designed for use in debuggersChema
From the docs: "This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately."Chema
Actually YES I just did yesterday, and I realized I was mistaken. I decided to remain silent on the matter, but you pointed it out, which is good.Ethiopian
M
2

A condition is always associated with a mutex. Usually, a thread will sleep because it's waiting for a change of state to indicate that it has work to do; you need the mutex to guard access to that state, and the condition to signal the change.

Waking up a thread without telling it why you've woken it is a bit of an odd thing to do, so there's no special way to do it; the only way to do it is to use the normal mechanism, but with no shared state.

If for some reason you want to suspend and resume the thread from another thread, independently from giving it work to do, then you might be able to use pthread_kill to send it SIGSTOP and SIGCONT signals; I've never tried doing anything like that, so I've no idea whether or not it's supported.

Meteorite answered 29/6, 2010 at 13:58 Comment(0)
C
0

Mutexes are used to ensure the exclusive access , where as condition variables are used to synchronize threads based on the events.

We need Mutexes to ensure that condition variables dont end up in an infinite wait. One thing to remember is Mutex operation of lock and unlock are guaranteed to be atomic, but the condition variables need not be. i.e The thread can get scheduled out while the condition variable wait is half way.

Consider the following case with out Mutex for condition variable.

Thread 1


1)Perform Some Operation
2)Wait on the Condition Variable
3)Continues the Operation

Thread 2


1) Perform some operation
2)Signal the Condition Variable
3)Continue the Operation

Here in the Thread 1 , the step 2 is not guaranteed to be atomic. If the Thread 1 is pushed out of RUNNING state by scheduler before it completes the step1. Now Thread 2 starts executing and signals the condition variable. When Thread 1 resumes execution it will finish the remaining low level instructions and starts waiting. Thread 1 ends up in an infinite wait, as the signal of condition variable occurred even before the wait.

So the Right way to use is (I believe the code mentioned in the question doesnt do the expected)

Thread 1 :-


1)Do work up to the point where a certain condition must occur (such as "count" must reach a specified value)
2)Lock associated mutex
3)Call pthread_cond_wait() to perform a blocking wait for signal from Thread1. ( Note that a call to pthread_cond_wait() automatically and atomically unlocks the associated mutex variable so that it can be used by Thread2)
4)When signalled, wake up. Mutex is automatically and atomically locked.
5)Explicitly unlock mutex

Thread2


1)Do work
2)Lock associated mutex
3)Change the value of the global variable that Thread1 is waiting upon.
4)Check value of the global Thread1 wait variable. If it fulfills the desired condition, signal Thread1.
5)Unlock mutex. Continue

Calabrese answered 29/6, 2010 at 14:0 Comment(0)
K
0

It looks like there are no any Linux alternatives to Windows API SuspendThread function. It is impossible to pause Linux thread without injection any code in that thread procedure.

Kutz answered 8/10, 2012 at 18:45 Comment(1)
SuspendThread in user-mode code is always smelly. Even the documentation says "This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization.", which should be enough for anybody wanting to use it.Kaolinite
P
0

The code posted answered Jun 29, 2010 by "caf" is correct and works well for synchronizing two cooperating threads.

Peltry answered 28/6, 2023 at 19:58 Comment(0)
G
-1

More to the point - what are you ultimately trying to do?? - I suspect the answer is not 'suspend a thread'. It may be that your program design has a problem.

Gonocyte answered 29/6, 2010 at 14:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.