📄 test_ncbithr.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: test_ncbithr.cpp,v $ * PRODUCTION Revision 1000.1 2004/06/01 19:10:21 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.7 * PRODUCTION * =========================================================================== *//* $Id: test_ncbithr.cpp,v 1000.1 2004/06/01 19:10:21 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Aleksey Grichenko * * File Description: * Test for multithreading classes * */#include <ncbi_pch.hpp>#include <corelib/ncbistd.hpp>#include <corelib/ncbiapp.hpp>#include <corelib/ncbithr.hpp>#include <corelib/ncbimtx.hpp>#include <corelib/ncbienv.hpp>#include <corelib/ncbiargs.hpp>#include <corelib/ncbidiag.hpp>#include <map>#include <test/test_assert.h> /* This header must go last */USING_NCBI_SCOPE;/////////////////////////////////////////////////////////////////////////////// Globalsconst int cNumThreadsMin = 1;const int cNumThreadsMax = 500;const int cSpawnByMin = 1;const int cSpawnByMax = 100;const int cRCyclesMin = 10;const int cRCyclesMax = 5000;const int cWCyclesMin = 5;const int cWCyclesMax = 1000;static int sNumThreads = 35;static int sSpawnBy = 6;static int sRCycles = 100;static int sWCycles = 50;static int s_NextIndex = 0;DEFINE_STATIC_FAST_MUTEX(s_GlobalLock);void delay(int value){ for (int i=0; i<value; i++) { CFastMutexGuard out_guard(s_GlobalLock); }}void TestTlsCleanup(int* p_value, void* p_ref){ // Copy current value, then delete it *static_cast<int*>(p_ref) = *p_value; delete p_value;}void Main_Thread_Tls_Cleanup(int* p_value, void* /* p_data */){ (*p_value)++;}/////////////////////////////////////////////////////////////////////////////// Shared resource imitation//// Imitates reading & writing of a shared resource.// Checks if there are violations of read-write locks.//class CSharedResource{public: CSharedResource(void) : m_Readers(0), m_Writer(-1) {} ~CSharedResource(void) { assert(!m_Readers); } void BeginRead(int ID); void BeginWrite(int ID); void EndRead(int ID); void EndWrite(int ID);private: int m_Readers; int m_Writer; CFastMutex m_Mutex;};void CSharedResource::BeginRead(int ID){ CFastMutexGuard guard(m_Mutex); // Must be unlocked, R-locked, or W-locked by the same thread assert(m_Readers >= 0 || (m_Readers < 0 && ID == m_Writer)); (m_Readers >= 0) ? m_Readers++ : m_Readers--;}void CSharedResource::BeginWrite(int ID){ CFastMutexGuard guard(m_Mutex); // Must be unlocked or W-locked by the same thread assert(m_Readers == 0 || (m_Readers < 0 && ID == m_Writer)); m_Readers--; m_Writer = ID;}void CSharedResource::EndRead(int ID){ CFastMutexGuard guard(m_Mutex); // Must be R-locked or W-locked by the same thread assert(m_Readers > 0 || (m_Readers < 0 && m_Writer == ID)); (m_Readers > 0) ? m_Readers-- : m_Readers++; if (m_Readers == 0) { m_Writer = -1; }}void CSharedResource::EndWrite(int ID){ CFastMutexGuard guard(m_Mutex); // Must be W-locked by the same thread; assert(m_Readers < 0 && m_Writer == ID); m_Readers++; if (m_Readers == 0) { m_Writer = -1; }}/////////////////////////////////////////////////////////////////////////////// Test threadclass CTestThread : public CThread{public: CTestThread(int index, CTls<int>* tls, CRWLock* rw, CSharedResource* res);protected: ~CTestThread(void); virtual void* Main(void); virtual void OnExit(void);private: int m_Index; // Thread sequential index CTls<int>* m_Tls; // Test TLS object int m_CheckValue; // Value to compare with the TLS data CRWLock* m_RW; // Test RWLock object CSharedResource* m_Res; // Shared resource imitation};// Thread states checked by the main threadenum TTestThreadState { eNull, // Initial value eCreated, // Set by CTestThread::CTestThread() eRunning, // Set by CTestThread::Main() eTerminated, // Set by CTestThread::OnExit() eDestroyed // Set by CTestThread::~CTestThread()};// Pointers to all threads and corresponding statesCTestThread* thr[cNumThreadsMax];TTestThreadState states[cNumThreadsMax];// Prevent threads from termination before Detach() or Join()CMutex* exit_locks[cNumThreadsMax];CTestThread::CTestThread(int index, CTls<int>* tls, CRWLock* rw, CSharedResource* res) : m_Index(index), m_Tls(tls), m_CheckValue(15), m_RW(rw), m_Res(res){ CFastMutexGuard guard(s_GlobalLock); states[m_Index] = eCreated;}CTestThread::~CTestThread(void){ CFastMutexGuard guard(s_GlobalLock); assert(m_CheckValue == 15); states[m_Index] = eDestroyed;}void CTestThread::OnExit(void){ CFastMutexGuard guard(s_GlobalLock); states[m_Index] = eTerminated;}bool Test_CThreadExit(void){ DEFINE_STATIC_FAST_MUTEX(s_Exit_Mutex); CFastMutexGuard guard(s_Exit_Mutex); // The mutex must be unlocked after call to CThread::Exit() try { CThread::Exit(reinterpret_cast<void*>(-1)); } catch (...) { throw; } return false; // this line should never be executed}void* CTestThread::Main(void){ {{ CFastMutexGuard guard(s_GlobalLock); states[m_Index] = eRunning; }} // ======= CTls test ======= // Verify TLS - initial value must be 0 m_CheckValue = 0; assert(m_Tls->GetValue() == 0); int* stored_value = new int; assert(stored_value != 0); *stored_value = 0; m_Tls->SetValue(stored_value, TestTlsCleanup, &m_CheckValue); for (int i=0; i<5; i++) { stored_value = new int; assert(stored_value != 0); *stored_value = *m_Tls->GetValue()+1; m_Tls->SetValue(stored_value, TestTlsCleanup, &m_CheckValue); assert(*stored_value == m_CheckValue+1); } // ======= CThread test ======= for (int i = 0; i<sSpawnBy; i++) { int idx; {{ CFastMutexGuard spawn_guard(s_GlobalLock); if (s_NextIndex >= sNumThreads) { break; } idx = s_NextIndex; s_NextIndex++; }} thr[idx] = new CTestThread(idx, m_Tls, m_RW, m_Res); assert(states[idx] == eCreated); thr[idx]->Run(); {{ CFastMutexGuard guard(s_GlobalLock); NcbiCout << idx << " "; }} } // ======= CTls test ======= // Verify TLS - current value must be 5 assert(*m_Tls->GetValue() == 5); for (int i=0; i<5; i++) { stored_value = new int; assert(stored_value != 0); *stored_value = *m_Tls->GetValue()+1; m_Tls->SetValue(stored_value, TestTlsCleanup, &m_CheckValue); assert(*stored_value == m_CheckValue+1); } // ======= CRWLock test ======= static int s_var = 0; // global value if (m_Index % 5) { // <------ Reader for (int r_cycle=0; r_cycle<sRCycles*2; r_cycle++) { // Lock immediately or wait for locking if (!m_RW->TryReadLock()) { m_RW->ReadLock(); } int l_var = s_var; // must remain the same while R-locked m_Res->BeginRead(m_Index); assert(l_var == s_var); // Cascaded R-lock if (r_cycle % 6 == 0) { m_RW->ReadLock(); m_Res->BeginRead(m_Index); } assert(l_var == s_var); // Cascaded R-lock must be allowed if (r_cycle % 12 == 0) { assert(m_RW->TryReadLock()); m_Res->BeginRead(m_Index); m_Res->EndRead(m_Index); m_RW->Unlock(); } // W-after-R must be prohibited assert( !m_RW->TryWriteLock() ); delay(10); // ======= CTls test ======= // Verify TLS - current value must be 10 assert(*m_Tls->GetValue() == 10); assert(l_var == s_var); // Cascaded R-lock must be allowed if (r_cycle % 7 == 0) { assert(m_RW->TryReadLock()); m_Res->BeginRead(m_Index); m_Res->EndRead(m_Index); m_RW->Unlock(); } assert(l_var == s_var); if (r_cycle % 6 == 0) { m_Res->EndRead(m_Index); m_RW->Unlock(); } assert(l_var == s_var); m_Res->EndRead(m_Index); m_RW->Unlock(); } } else { // <------ Writer for (int w_cycle=0; w_cycle<sWCycles; w_cycle++) { // Lock immediately or wait for locking if (!m_RW->TryWriteLock()) { m_RW->WriteLock(); } m_Res->BeginWrite(m_Index); // Cascaded W-lock if (w_cycle % 4 == 0) { m_RW->WriteLock(); m_Res->BeginWrite(m_Index); } // R-after-W (treated as cascaded W-lock) if (w_cycle % 6 == 0) { m_RW->ReadLock(); m_Res->BeginRead(m_Index); } // Cascaded W-lock must be allowed if (w_cycle % 8 == 0) { assert(m_RW->TryWriteLock()); m_Res->BeginWrite(m_Index); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -