92 lines
3.5 KiB
C++
92 lines
3.5 KiB
C++
// File: crn_condition_var.h
|
|
// See Copyright Notice and license at the end of inc/crnlib.h
|
|
// Inspired by the "monitor" class in "Win32 Multithreaded Programming" by Cohen and Woodring.
|
|
// Also see http://en.wikipedia.org/wiki/Monitor_(synchronization)
|
|
#pragma once
|
|
|
|
#include "crn_mutex.h"
|
|
#include "crn_event.h"
|
|
#include "crn_semaphore.h"
|
|
|
|
namespace crnlib
|
|
{
|
|
class condition_var
|
|
{
|
|
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(condition_var);
|
|
|
|
public:
|
|
condition_var(uint spin_count = 4096U);
|
|
~condition_var();
|
|
|
|
// Locks the condition_var.
|
|
// Recursive locks are supported.
|
|
void lock();
|
|
|
|
// Returns TRUE if the thread owning this condition function should stop waiting.
|
|
// This function will always be called from within the condition_var, but it may be called from several different threads!
|
|
typedef bool (*pCondition_func)(void* pCallback_data_ptr, uint64 callback_data);
|
|
|
|
// Temporarily leaves the lock and waits for a condition to be satisfied.
|
|
// If pCallback is NULL, this method will return after another thread enters and exits the lock (like a Vista-style condition variable).
|
|
// Otherwise, this method will only return when the specified condition function returns TRUE when another thread exits the lock.
|
|
// When this method returns, the calling thread will be inside the lock.
|
|
// Returns -1 on timeout or error, 0 if the wait was satisfied, or 1 or higher if one of the extra wait handles became signaled.
|
|
// It is highly recommended you use a non-null condition callback. If you don't be sure to check for race conditions!
|
|
int wait(pCondition_func pCallback = NULL, void* pCallback_data_ptr = NULL, uint64 callback_data = 0,
|
|
uint num_wait_handles = 0, const void** pWait_handles = NULL, uint32 max_time_to_wait = UINT32_MAX);
|
|
|
|
// Unlocks the condition_var. Another thread may be woken up if its condition function has become satisfied.
|
|
void unlock();
|
|
|
|
uint32 get_cur_lock_count() const;
|
|
|
|
private:
|
|
enum { cMaxWaitingThreads = 16, cMaxWaitingThreadsMask = cMaxWaitingThreads - 1 };
|
|
|
|
semaphore m_condition_var_lock;
|
|
mutex m_waiters_array_lock;
|
|
uint32 m_tls;
|
|
uint m_cur_age;
|
|
|
|
struct waiting_thread
|
|
{
|
|
uint64 m_callback_data;
|
|
void* m_pCallback_ptr;
|
|
pCondition_func m_callback_func;
|
|
uint m_age;
|
|
bool m_satisfied;
|
|
bool m_occupied;
|
|
|
|
event m_event;
|
|
|
|
void clear()
|
|
{
|
|
m_callback_data = 0;
|
|
m_pCallback_ptr = NULL;
|
|
m_callback_func = NULL;
|
|
m_age = 0;
|
|
m_satisfied = false;
|
|
m_occupied = false;
|
|
}
|
|
};
|
|
waiting_thread m_waiters[cMaxWaitingThreads];
|
|
|
|
int m_max_waiter_array_index;
|
|
|
|
void set_cur_lock_count(uint32 newCount);
|
|
|
|
void leave_and_scan(int index_to_ignore = -1);
|
|
};
|
|
|
|
class scoped_condition_var
|
|
{
|
|
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(scoped_condition_var);
|
|
public:
|
|
inline scoped_condition_var(condition_var& m) : m_condition_var(m) { m_condition_var.lock(); }
|
|
inline ~scoped_condition_var() { m_condition_var.unlock(); }
|
|
private:
|
|
condition_var& m_condition_var;
|
|
};
|
|
|
|
} // namespace crnlib
|