I have a weird problem with pthread_cond_wait and pthread_cond_signal. I have arranged a series of threads. They are all in sleep state when started. A wake up function will signal these threads, do some work, and wait for the results.
In the setup below, td is thread data, containing the mutex and conditions, and th is an array containing the pointer to the threads:
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_cond_init(&td[i].cond, NULL);
pthread_mutex_init(&td[i].cond_mutex, NULL);
pthread_mutex_init(&td[i].work_mutex, NULL);
pthread_mutex_lock(&td[i].cond_mutex);
pthread_mutex_lock(&td[i].work_mutex);
pthread_create(&th[i], NULL, thread_worker, (void *)&td[i]);
}
Thread worker is like this:
void*
thread_worker(void* data)
{
THREAD_DATA *td = (THREAD_DATA *)data;
while (1) {
pthread_cond_wait(&td->cond, &td->cond_mutex); // marker
// do work ...
pthread_mutex_unlock(&td->work_mutex);
}
pthread_exit(NULL);
}
This job function is supposed to wake up all the threads, do the job, and wait for them to finish:
void
job()
{
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_cond_signal(&td[i].cond);
}
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_mutex_lock(&td[i].work_mutex); // block until the work is done
}
}
In some rare situations (1 out of 1000 runs maybe), the above setup will encounter a freeze. When that happens, the 'marker' line in thread_worker will not be signaled by pthread_cond_signal, it just kept on waiting. It's very rare but it happens from time to time. I've produced numerous log messages, and I verified that pthread_cond_wait is always called before pthread_cond_signal. What am I doing wrong here?
There is nothing there that forces the pthread_cond_wait() to be called before the pthread_cond_signal(). Despite what you say about logging, it's entirely possible for the logged lines to be out-of-sequence with what really happened.
You aren't using mutexes and condition variables correctly: mutexes should only be unlocked by the same thread that locked them, and condition variables should be paired with a test over some shared state (called a predicate). The shared state is supposed to be protected by the mutex that is passed to pthread_cond_wait().
For example, your example can be reworked to correctly use mutexes and condition variables. First, add an int work_status to the THREAD_DATA structure, where 0 indicates that the thread is waiting for work, 1 indicates that work is available and 2 indicates that the work is complete.
You don't appear to need two mutexes in each THREAD_DATA, and you don't want to lock the mutex in the main thread when you're setting it up:
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_cond_init(&td[i].cond, NULL);
pthread_mutex_init(&td[i].cond_mutex, NULL);
td[i].work_status = 0;
pthread_create(&th[i], NULL, thread_worker, (void *)&td[i]);
}
Have the threads wait on work_status using the condition variable:
void*
thread_worker(void* data)
{
THREAD_DATA *td = (THREAD_DATA *)data;
while (1) {
/* Wait for work to be available */
pthread_mutex_lock(&td->cond_mutex);
while (td->work_status != 1)
pthread_cond_wait(&td->cond, &td->cond_mutex);
pthread_mutex_unlock(&td->cond_mutex);
// do work ...
/* Tell main thread that the work has finished */
pthread_mutex_lock(&td->cond_mutex);
td->work_status = 2;
pthread_cond_signal(&td->cond);
pthread_mutex_unlock(&td->cond_mutex);
}
pthread_exit(NULL);
}
...and set and wait on work_status as appropriate in job():
void
job()
{
/* Tell threads that work is available */
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_mutex_lock(&td[i].cond_mutex);
td[i].work_status = 1;
pthread_cond_signal(&td[i].cond);
pthread_mutex_unlock(&td[i].cond_mutex);
}
/* Wait for threads to signal work complete */
for (size_t i = 0; i < NUM_THREADS; i++) {
pthread_mutex_lock(&td[i].cond_mutex);
while (td[i].work_status != 2)
pthread_cond_wait(&td[i].cond, &td[i].cond_mutex);
pthread_mutex_unlock(&td[i].cond_mutex);
}
}
Some check lists:
1) Do you lock the mutex td->cond_mutex before waiting on the cond variable? Otherwise, it's undefined.
2) Do you check predicate after pthread_cond_wait() returns? Typical usage is
while(!flag) pthread_cond_wait(&cv, &mutex); //waits on flag
which is not what you have. This is to protect against spurious wake-ups and also ensure the predicate hasn't changed in the meantime.
3) pthread_cond_signal() is guaranteed to wake up at least one thread. You may want to use pthread_cond_broadcast() if there are multiple threads waiting on the same condition variable.
4) If no thread is waiting on a conditional variable then pthread_cond_signal() or pthread_cond_broadcast() has no effect.
Related
I have a problem with my code:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <windows.h>
#include <string.h>
#include <math.h>
HANDLE event;
HANDLE mutex;
int runner = 0;
DWORD WINAPI thread_fun(LPVOID lpParam) {
int* data = (int*)lpParam;
for (int j = 0; j < 4; j++) { //this loop necessary in order to reproduce the issue
if ((data[2] + 1) == data[0]) { // if it is last thread
while (1) {
WaitForSingleObject(mutex, INFINITE);
if (runner == data[0] - 1) { // if all other thread reach event break
ReleaseMutex(mutex);
break;
}
printf("Run:%d\n", runner);
ReleaseMutex(mutex);
Sleep(10);
}
printf("Check Done:<<%d>>\n", data[2]);
runner = 0;
PulseEvent(event); // let all other threads continue
}
else { // if it is not last thread
WaitForSingleObject(mutex, INFINITE);
runner++;
ReleaseMutex(mutex);
printf("Wait:<<%d>>\n", data[2]);
WaitForSingleObject(event, INFINITE); // wait till all other threads reach this stage
printf("Exit:<<%d>>\n", data[2]);
}
}
return 0;
}
int main()
{
event = CreateEvent(NULL, TRUE, FALSE, NULL);
mutex = CreateMutex(NULL, FALSE, NULL);
SetEvent(event);
int data[3] = {2,8}; //0 amount of threads //1 amount of numbers
HANDLE t[10000];
int ThreadData[1000][3];
for (int i = 0; i < data[0]; i++) {
memcpy(ThreadData[i], data, sizeof(int) * 2); // copy amount of threads and amount of numbers to the threads data
ThreadData[i][2] = i; // creat threads id
LPVOID ThreadsData = (LPVOID)(&ThreadData[i]);
t[i] = CreateThread(0, 0, thread_fun, ThreadsData, 0, NULL);
if (t[i] == NULL)return 0;
}
while (1) {
DWORD res = WaitForMultipleObjects(data[0], t, true, 1000);
if (res != WAIT_TIMEOUT) break;
}
for (int i = 0; i < data[0]; i++)CloseHandle(t[i]); // close all threads
CloseHandle(event); // close event
CloseHandle(mutex); //close mutex
printf("Done");
}
The main idea is to wait until all threads except one reach the event and wait there, meanwhile the last thread must release them from waiting.
But the code doesn't work reliably. 1 in 10 times, it ends correctly, and 9 times just gets stuck in while(1). In different tries, printf in while (printf("Run:%d\n", runner);) prints different numbers of runners (0 and 3).
What can be the problem?
As we found out in the comments section, the problem was that although the event was created in the initial state of being non-signalled
event = CreateEvent(NULL, TRUE, FALSE, NULL);
it was being set to the signalled state immediately afterwards:
SetEvent(event);
Due to this, at least on the first iteration of the loop, when j == 0, the first worker thread wouldn't wait for the second worker thread, which caused a race condition.
Also, the following issues with your code are worth mentioning (although these issues were not the reason for your problem):
According to the Microsoft documentation on PulseEvent, that function should not be used, as it can be unreliable and is mainly provided for backward-compatibility. According to the documentation, you should use condition variables instead.
In your function thread_fun, the last thread is locking and releasing the mutex in a loop. This can be bad, because mutexes are not guaranteed to be fair and it is possible that this will cause other threads to never be able to acquire the mutex. Although this possibility is mitigated by you calling Sleep(10); once in every loop iteration, it is still not the ideal solution. A better solution would be to use a condition variable, so that the thread only checks for changes of the variable runner when another thread actually signals a possible change. Such a solution would also be better for performance reasons.
I'm having a problem where I'm having a few condition_variable's get stuck in their wait phase even though they've been notified. Each one even has a predicate that's being set just in case they miss the notify call from the main thread.
Here's the code:
unsigned int notifyCount = 10000;
std::atomic<int> threadCompletions = 0;
for (unsigned int i = 0; i < notifyCount; i++)
{
std::atomic<bool>* wakeUp = new std::atomic<bool>(false);
std::condition_variable* condition = new std::condition_variable();
// Worker thread //
std::thread([&, condition, wakeUp]()
{
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
condition->wait(lock, [wakeUp] { return wakeUp->load(); });
threadCompletions++;
}).detach();
// Notify //
*wakeUp = true;
condition->notify_one();
}
Sleep(5000); // Sleep for 5 seconds just in case some threads are taking a while to finish executing
// Check how many threads finished (threadCompletions should be equal to notifyCount)
Unless I'm mistaken, after the for loop is done, threadCompletions should always be equal to notifyCount. Very often though, it is not.
When running in release, I'll sometimes get just one or two out of 10000 threads that never finished, but when running in debug, I'll get 20 or more.
I thought maybe the wait call in the thread is happening after the main thread's notify_one call (meaning it missed it's notification to wake up), so I passed a predicate into wait to insure that it doesn't get stuck waiting. But it still does in some cases.
Does anyone know why this is happening?
You are assuming the call to wait() is atomic. I don't believe it is. That is why it requires the use of a mutex and a lock.
Consider the following:
Main Thread. Child Thread
// This is your wait unrolled.
while (!wakeUp->load()) {
// This is atomic
// But already checked in the
// thread.
*wakeUp = true;
// Child has not yet called wait
// So this notify_one is wasted.
condition->notify_one();
// The previous call to notify_one
// is not recorded and thus the
// thread is now locked in this wait
// never to be let free.
wait(lock);
}
// Your race condition.
Calls to notify_one() and wait() should be controlled via the same mutext to make sure they don't overlap like this.
for (unsigned int i = 0; i < notifyCount; i++)
{
std::atomic<bool>* wakeUp = new std::atomic<bool>(false);
std::mutex* mutex = new std::mutex{};
std::condition_variable* condition = new std::condition_variable();
// Worker thread //
std::thread([&]()
{
std::unique_lock<std::mutex> lock(*mutex);
condition->wait(lock, [&wakeUp] { return wakeUp->load(); });
threadCompletions++;
}).detach();
// Notify //
*wakeUp = true;
std::unique_lock<std::mutex> lock(*mutex);
condition->notify_one();
}
// Don't forget to clean up the new structures correctly/.
You have data racing. Consider following scenario:
Worker Thread: condition variable tests for whether wakeup is true - it isn't
Main Thread: wakeup is set to true and condition variable is getting notified
Worker Thread: condition_variable triggers wait but it happens after notification already occurred - impling that notification misses and the thread might never wake up.
Normally, synchronization of condition variables is done via mutexes - atomics aren't too helpful here. In C++20 there will be special mechanism for waiting/notifying in atomics.
I am attempting to write a thread safe task queue for multithreading in C++, using SDL2's threading library.
The thread function which runs on all threads is as follows:
int threadFunc(void * pData)
{
ThreadData* data = (ThreadData*)pData;
SDLTaskManager* pool = data->pool;
Task* task = nullptr;
while (true)
{
SDL_LockMutex(pool->mLock);
while (!pool->mRunning && pool->mCurrentTasks.empty())
{
//mutex is unlocked, then locked again when signal received
SDL_CondWait(pool->mConditionFlag, pool->mLock);
if (pool->mShuttingDown)
return 0;
}
//mutex is locked at this stage so no other threads can alter contents of deque
//code inside if block should not be executed if deque is empty
if (!pool->mCurrentTasks.empty())
{
/*out of range error here*/
task = pool->mCurrentTasks.front();
pool->mCurrentTasks.pop_front();
}
if (task != nullptr)
{
pool->notifyThreadWorking(true);
data->taskCount++;
}
else
{
pool->stop();
SDL_UnlockMutex(pool->mLock);
continue;
}
SDL_UnlockMutex(pool->mLock);
task->execute();
SDL_LockMutex(pool->mLock);
pool->notifyThreadWorking(false);
pool->mCompleteTasks.push_back(task);
SDL_UnlockMutex(pool->mLock);
task = nullptr;
}
return 0;
}
As you can see, according to the comments in the code, an out of range error occurs inside an if block, where the deque is empty. However, there is a check there to make sure that the code is only executed if the deque is not empty. The mutex is locked by SDL_CondWait so no other thread should be able to make changes to the deque, until that mutex is unlocked again.
The producer code is as follows:
SDL_LockMutex(pool->mLock);
for (int i = 0; i < numTasks; i++)
{
pool->mCurrentTasks.push_back(new Task());
}
pool->mRunning = true;
SDL_CondBroadcast(pool->mConditionFlag);
SDL_UnlockMutex(pool->mLock);
The fact that the code inside the if block is being executed, shows that at the time if (!pool->mCurrentTasks.empty()) is evaluated, the deque has member data, but not when it reaches task = pool->mCurrentTasks.front(); By my understanding of mutex' this shouldn't be possible. How can this be?
I am writing code for a memory buffer which allows threads to share memory with each other. I am trying to use critical sections and condition variables for synchronization.
Here is my source code:
size_t ReadBuffer(char *dst_buffer)
{
size_t size = 0;
EnterCriticalSection(&m_CriticalSection);
if (!m_bBufferReady)
{
printf("ReadBuffer: wait for ready buffer\n");
SleepConditionVariableCS (&BufferNotEmpty, &m_CriticalSection, INFINITE);
printf("ReadBuffer: after wait for ready buffer\n");
}
if (m_uRealSize == 0)
{
}
memcpy(dst_buffer, m_pBuffer, m_uRealSize);
size = m_uRealSize;
m_uRealSize = 0;
m_bBufferReady = FALSE;
LeaveCriticalSection(&m_CriticalSection);
WakeConditionVariable (&BufferNotFull);
if (size != 0)
{
SleepConditionVariableCS (&BufferNotEmpty, &m_CriticalSection, INFINITE);
}
return size;
}
size_t WriteBuffer(const char *src_buffer, size_t size)
{
EnterCriticalSection(&m_CriticalSection);
if (m_bBufferReady)
{
SleepConditionVariableCS (&BufferNotFull, &m_CriticalSection, INFINITE);
printf("WriteBuffer: after wait for free buffer\n");
}
if (size > m_uBufferSize)
size = m_uBufferSize;
memcpy(m_pBuffer, src_buffer, size);
m_uRealSize = size;
m_bBufferReady = TRUE;
LeaveCriticalSection(&m_CriticalSection);
WakeConditionVariable (&BufferNotEmpty);
SleepConditionVariableCS (&BufferNotFull, &m_CriticalSection, INFINITE);
return size;
}
When WriteBuffer is called with a zero size buffer it is treated as the end of communication. At that point the reading thread exits correctly but the writing thread hangs on the last call to SleepConditionVariableCS.
When I use Windows events instead of conditional variables, everything works OK, so I don't think this is a problem with the algorithm. But I want to be able to use conditional variables instead of events. Is there some restriction to the use of conditional variables? Or maybe it is connected to the critical section somehow?
What is going wrong, and how can I fix it?
I think the first problem is that you're calling SleepConditionalVariableCS after exiting the critical section.
From the documentation for SleepConditionVariableCS:
This critical section must be entered exactly once by the caller at the time SleepConditionVariableCS is called.
As described in the documentation for LeaveCriticalSection, exiting a critical section you don't own causes an error that "may cause another thread using EnterCriticalSection to wait indefinitely".
I am coding a telemetry system in C++ and have been having some difficulty syncing certain threads with the standard pthread_cond_timedwait and pthread_cond_broadcast.
The problem was that I needed some way for the function that was doing the broadcasting to know if another thread acted on the broadcast.
After some hearty searching I decided I might try using a barrier for the two threads instead. However, I still wanted the timeout functionality of the pthread_cond_timedwait.
Here is basically what I came up with: (However it feels excessive)
Listen Function: Checks for a period of milliseconds to see if an event is currently being triggered.
bool listen(uint8_t eventID, int timeout)
{
int waitCount = 0;
while(waitCount <= timeout)
{
globalEventID = eventID;
if(getUpdateFlag(eventID) == true)
{
pthread_barrier_wait(&barEvent);
return true;
}
threadSleep(); //blocks for 1 millisecond
++waitCount;
}
return false;
}
Trigger Function: Triggers an event for a period of milliseconds by setting an update flag for the triggering period
bool trigger(uint8_t eventID, int timeout)
int waitCount = 0;
while(waitCount <= timeout)
{
setUpdateFlag(eventID, true); //Sets the update flag to true
if(globalEventID == eventID)
{
pthread_barrier_wait(&barEvent);
return true;
}
threadSleep(); //blocks for 1 millisecond
++waitCount;
}
setUpdateFlag(eventID, false);
return false;
}
My questions: Is another way to share information with the broadcaster, or are barriers really the only efficient way? Also, is there another way of getting timeout functionality with barriers?
Based on your described problem:
Specifically, I am trying to let thread1 know that the message it is
waiting for has been parsed and stored in a global list by thread2,
and that thread2 can continue parsing and storing because thread1 will
now copy that message from the list ensuring that thread2 can
overwrite that message with a new version and not disrupt the
operations of thread1.
It sounds like your problem can be solved by having both threads alternately wait on the condition variable. Eg. in thread 1:
pthread_mutex_lock(&mutex);
while (!message_present)
pthread_cond_wait(&cond, &mutex);
copy_message();
message_present = 0;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
process_message();
and in thread 2:
parse_message();
pthread_mutex_lock(&mutex);
while (message_present)
pthread_cond_wait(&cond, &mutex);
store_message();
message_present = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);