This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user