using ::nlib_ns::threading::ScopedLock;
using ::nlib_ns::threading::UniqueLock;
using ::nlib_ns::threading::CondVar;
using ::nlib_ns::threading::SimpleCriticalSection;
using ::nlib_ns::threading::Thread;
const int NUM_THREADS = 6;
Thread g_Th[NUM_THREADS];
struct CondVarState {
CondVar cond;
SimpleCriticalSection lock;
bool flag;
public:
CondVarState() : flag(false) {}
} g_Cond1, g_Cond2;
class ThreadParam {
public:
ThreadParam() : m_ThreadNum(0), m_Status(false), m_Wait(NULL), m_Signal(NULL) {}
void Initialize(int num, CondVarState* w, CondVarState* s) {
m_ThreadNum = num;
m_Wait = w;
m_Signal = s;
m_Status = true;
}
void Exec();
static void ThreadFunc(ThreadParam* param) { param->Exec(); }
bool IsSuccessful() { return m_Status; }
private:
int m_ThreadNum;
bool m_Status;
CondVarState* m_Wait;
CondVarState* m_Signal;
};
void ThreadParam::Exec() {
{
UniqueLock<SimpleCriticalSection> lock(m_Wait->lock);
while (!m_Wait->flag) {
errno_t e = m_Wait->cond.Wait(lock);
if (e != 0) {
m_Status = false;
return;
}
nlib_printf(
" Thread %d may be notified and acquires lock\n", m_ThreadNum);
}
nlib_printf(
" Thread %d is notified, and do its own job\n", m_ThreadNum);
m_Wait->flag = false;
}
{
ScopedLock<SimpleCriticalSection> lock(m_Signal->lock);
m_Signal->flag = true;
m_Signal->cond.NotifyAll();
}
}
bool CondVarDemo() {
ThreadParam param[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; ++i) {
if (i % 2 == 0) {
param[i].Initialize(i, &g_Cond1, &g_Cond2);
e = g_Th[i].Start(ThreadParam::ThreadFunc, ¶m[i]);
} else {
param[i].Initialize(i, &g_Cond2, &g_Cond1);
e = g_Th[i].Start(ThreadParam::ThreadFunc, ¶m[i]);
}
if (e != 0) return false;
}
g_Cond1.lock.lock();
g_Cond1.flag = true;
g_Cond1.cond.NotifyAll();
g_Cond1.lock.unlock();
for (int i = 0; i < NUM_THREADS; ++i) {
e = g_Th[i].Join();
if (e != 0) return false;
}
for (int i = 0; i < NUM_THREADS; ++i) {
if (!param[i].IsSuccessful()) return false;
}
return true;
}
static bool SampleMain(int, char**) { return CondVarDemo(); }
NLIB_MAINFUNC