test_ncbithr.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:22k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: test_ncbithr.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:10:21  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.7
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: test_ncbithr.cpp,v 1000.1 2004/06/01 19:10:21 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Aleksey Grichenko
  35.  *
  36.  * File Description:
  37.  *   Test for multithreading classes
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include <corelib/ncbistd.hpp>
  42. #include <corelib/ncbiapp.hpp>
  43. #include <corelib/ncbithr.hpp>
  44. #include <corelib/ncbimtx.hpp>
  45. #include <corelib/ncbienv.hpp>
  46. #include <corelib/ncbiargs.hpp>
  47. #include <corelib/ncbidiag.hpp>
  48. #include <map>
  49. #include <test/test_assert.h>  /* This header must go last */
  50. USING_NCBI_SCOPE;
  51. /////////////////////////////////////////////////////////////////////////////
  52. // Globals
  53. const int   cNumThreadsMin = 1;
  54. const int   cNumThreadsMax = 500;
  55. const int   cSpawnByMin    = 1;
  56. const int   cSpawnByMax    = 100;
  57. const int   cRCyclesMin    = 10;
  58. const int   cRCyclesMax    = 5000;
  59. const int   cWCyclesMin    = 5;
  60. const int   cWCyclesMax    = 1000;
  61. static int  sNumThreads    = 35;
  62. static int  sSpawnBy       = 6;
  63. static int  sRCycles       = 100;
  64. static int  sWCycles       = 50;
  65. static int  s_NextIndex    = 0;
  66. DEFINE_STATIC_FAST_MUTEX(s_GlobalLock);
  67. void delay(int value)
  68. {
  69.     for (int i=0; i<value; i++) {
  70.         CFastMutexGuard out_guard(s_GlobalLock);
  71.     }
  72. }
  73. void TestTlsCleanup(int* p_value, void* p_ref)
  74. {
  75.     // Copy current value, then delete it
  76.     *static_cast<int*>(p_ref) = *p_value;
  77.     delete p_value;
  78. }
  79. void Main_Thread_Tls_Cleanup(int* p_value, void* /* p_data */)
  80. {
  81.     (*p_value)++;
  82. }
  83. /////////////////////////////////////////////////////////////////////////////
  84. // Shared resource imitation
  85. //
  86. //   Imitates reading & writing of a shared resource.
  87. //   Checks if there are violations of read-write locks.
  88. //
  89. class CSharedResource
  90. {
  91. public:
  92.     CSharedResource(void) : m_Readers(0),
  93.                             m_Writer(-1) {}
  94.     ~CSharedResource(void) { assert(!m_Readers); }
  95.     void BeginRead(int ID);
  96.     void BeginWrite(int ID);
  97.     void EndRead(int ID);
  98.     void EndWrite(int ID);
  99. private:
  100.     int m_Readers;
  101.     int m_Writer;
  102.     CFastMutex m_Mutex;
  103. };
  104. void CSharedResource::BeginRead(int ID)
  105. {
  106.     CFastMutexGuard guard(m_Mutex);
  107.     // Must be unlocked, R-locked, or W-locked by the same thread
  108.     assert(m_Readers >= 0 || (m_Readers < 0 && ID == m_Writer));
  109.     (m_Readers >= 0) ? m_Readers++ : m_Readers--;
  110. }
  111. void CSharedResource::BeginWrite(int ID)
  112. {
  113.     CFastMutexGuard guard(m_Mutex);
  114.     // Must be unlocked or W-locked by the same thread
  115.     assert(m_Readers == 0 || (m_Readers < 0 && ID == m_Writer));
  116.     m_Readers--;
  117.     m_Writer = ID;
  118. }
  119. void CSharedResource::EndRead(int ID)
  120. {
  121.     CFastMutexGuard guard(m_Mutex);
  122.     // Must be R-locked or W-locked by the same thread
  123.     assert(m_Readers > 0 || (m_Readers < 0 && m_Writer == ID));
  124.     (m_Readers > 0) ? m_Readers-- : m_Readers++;
  125.     if (m_Readers == 0) {
  126.         m_Writer = -1;
  127.     }
  128. }
  129. void CSharedResource::EndWrite(int ID)
  130. {
  131.     CFastMutexGuard guard(m_Mutex);
  132.     // Must be W-locked by the same thread;
  133.     assert(m_Readers < 0 && m_Writer == ID);
  134.     m_Readers++;
  135.     if (m_Readers == 0) {
  136.         m_Writer = -1;
  137.     }
  138. }
  139. /////////////////////////////////////////////////////////////////////////////
  140. // Test thread
  141. class CTestThread : public CThread
  142. {
  143. public:
  144.     CTestThread(int index, CTls<int>* tls, CRWLock* rw, CSharedResource* res);
  145. protected:
  146.     ~CTestThread(void);
  147.     virtual void* Main(void);
  148.     virtual void  OnExit(void);
  149. private:
  150.     int              m_Index;        // Thread sequential index
  151.     CTls<int>*       m_Tls;          // Test TLS object
  152.     int              m_CheckValue;   // Value to compare with the TLS data
  153.     CRWLock*         m_RW;           // Test RWLock object
  154.     CSharedResource* m_Res;         // Shared resource imitation
  155. };
  156. // Thread states checked by the main thread
  157. enum   TTestThreadState {
  158.     eNull,          // Initial value
  159.     eCreated,       // Set by CTestThread::CTestThread()
  160.     eRunning,       // Set by CTestThread::Main()
  161.     eTerminated,    // Set by CTestThread::OnExit()
  162.     eDestroyed      // Set by CTestThread::~CTestThread()
  163. };
  164. // Pointers to all threads and corresponding states
  165. CTestThread*        thr[cNumThreadsMax];
  166. TTestThreadState    states[cNumThreadsMax];
  167. // Prevent threads from termination before Detach() or Join()
  168. CMutex*             exit_locks[cNumThreadsMax];
  169. CTestThread::CTestThread(int index,
  170.                          CTls<int>* tls,
  171.                          CRWLock* rw,
  172.                          CSharedResource* res)
  173.     : m_Index(index),
  174.       m_Tls(tls),
  175.       m_CheckValue(15),
  176.       m_RW(rw),
  177.       m_Res(res)
  178. {
  179.     CFastMutexGuard guard(s_GlobalLock);
  180.     states[m_Index] = eCreated;
  181. }
  182. CTestThread::~CTestThread(void)
  183. {
  184.     CFastMutexGuard guard(s_GlobalLock);
  185.     assert(m_CheckValue == 15);
  186.     states[m_Index] = eDestroyed;
  187. }
  188. void CTestThread::OnExit(void)
  189. {
  190.     CFastMutexGuard guard(s_GlobalLock);
  191.     states[m_Index] = eTerminated;
  192. }
  193. bool Test_CThreadExit(void)
  194. {
  195.     DEFINE_STATIC_FAST_MUTEX(s_Exit_Mutex);
  196.     CFastMutexGuard guard(s_Exit_Mutex);
  197.     // The mutex must be unlocked after call to CThread::Exit()
  198.     try {
  199.         CThread::Exit(reinterpret_cast<void*>(-1));
  200.     }
  201.     catch (...) {
  202.         throw;
  203.     }
  204.     return false;   // this line should never be executed
  205. }
  206. void* CTestThread::Main(void)
  207. {
  208.     {{
  209.         CFastMutexGuard guard(s_GlobalLock);
  210.         states[m_Index] = eRunning;
  211.     }}
  212.     // ======= CTls test =======
  213.     // Verify TLS - initial value must be 0
  214.     m_CheckValue = 0;
  215.     assert(m_Tls->GetValue() == 0);
  216.     int* stored_value = new int;
  217.     assert(stored_value != 0);
  218.     *stored_value = 0;
  219.     m_Tls->SetValue(stored_value, TestTlsCleanup, &m_CheckValue);
  220.     for (int i=0; i<5; i++) {
  221.         stored_value = new int;
  222.         assert(stored_value != 0);
  223.         *stored_value = *m_Tls->GetValue()+1;
  224.         m_Tls->SetValue(stored_value,
  225.                         TestTlsCleanup, &m_CheckValue);
  226.         assert(*stored_value == m_CheckValue+1);
  227.     }
  228.     // ======= CThread test =======
  229.     for (int i = 0; i<sSpawnBy; i++) {
  230.         int idx;
  231.         {{
  232.             CFastMutexGuard spawn_guard(s_GlobalLock);
  233.             if (s_NextIndex >= sNumThreads) {
  234.                 break;
  235.             }
  236.             idx = s_NextIndex;
  237.             s_NextIndex++;
  238.         }}
  239.         thr[idx] = new CTestThread(idx, m_Tls, m_RW, m_Res);
  240.         assert(states[idx] == eCreated);
  241.         thr[idx]->Run();
  242.         {{
  243.             CFastMutexGuard guard(s_GlobalLock);
  244.             NcbiCout << idx << " ";
  245.         }}
  246.     }
  247.     // ======= CTls test =======
  248.     // Verify TLS - current value must be 5
  249.     assert(*m_Tls->GetValue() == 5);
  250.     for (int i=0; i<5; i++) {
  251.         stored_value = new int;
  252.         assert(stored_value != 0);
  253.         *stored_value = *m_Tls->GetValue()+1;
  254.         m_Tls->SetValue(stored_value,
  255.                         TestTlsCleanup, &m_CheckValue);
  256.         assert(*stored_value == m_CheckValue+1);
  257.     }
  258.     // ======= CRWLock test =======
  259.     static int s_var = 0; // global value
  260.     if (m_Index % 5) {         // <------ Reader
  261.         for (int r_cycle=0; r_cycle<sRCycles*2; r_cycle++) {
  262.             // Lock immediately or wait for locking
  263.             if (!m_RW->TryReadLock()) {
  264.                 m_RW->ReadLock();
  265.             }
  266.             int l_var = s_var;    // must remain the same while R-locked
  267.             
  268.             m_Res->BeginRead(m_Index);
  269.             assert(l_var == s_var);
  270.             // Cascaded R-lock
  271.             if (r_cycle % 6 == 0) {
  272.                 m_RW->ReadLock();
  273.                 m_Res->BeginRead(m_Index);
  274.             }
  275.             assert(l_var == s_var);
  276.             // Cascaded R-lock must be allowed
  277.             if (r_cycle % 12 == 0) {
  278.                 assert(m_RW->TryReadLock());
  279.                 m_Res->BeginRead(m_Index);
  280.                 m_Res->EndRead(m_Index);
  281.                 m_RW->Unlock();
  282.     }
  283.             // W-after-R must be prohibited
  284.             assert( !m_RW->TryWriteLock() );
  285.             delay(10);
  286.             // ======= CTls test =======
  287.             // Verify TLS - current value must be 10
  288.             assert(*m_Tls->GetValue() == 10);
  289.             assert(l_var == s_var);
  290.             // Cascaded R-lock must be allowed
  291.             if (r_cycle % 7 == 0) {
  292.                 assert(m_RW->TryReadLock());
  293.                 m_Res->BeginRead(m_Index);
  294.                 m_Res->EndRead(m_Index);
  295.                 m_RW->Unlock();
  296.             }
  297.             assert(l_var == s_var);
  298.             if (r_cycle % 6 == 0) {
  299.                 m_Res->EndRead(m_Index);
  300.                 m_RW->Unlock();
  301.             }
  302.             assert(l_var == s_var);
  303.             m_Res->EndRead(m_Index);
  304.             m_RW->Unlock();
  305.         }
  306.     }
  307.     else {                     // <------ Writer
  308.         for (int w_cycle=0; w_cycle<sWCycles; w_cycle++) {
  309.             // Lock immediately or wait for locking
  310.             if (!m_RW->TryWriteLock()) {
  311.                 m_RW->WriteLock();
  312.             }
  313.             m_Res->BeginWrite(m_Index);
  314.             // Cascaded W-lock
  315.             if (w_cycle % 4 == 0) {
  316.                 m_RW->WriteLock();
  317.                 m_Res->BeginWrite(m_Index);
  318.             }
  319.             // R-after-W (treated as cascaded W-lock)
  320.             if (w_cycle % 6 == 0) {
  321.                 m_RW->ReadLock();
  322.                 m_Res->BeginRead(m_Index);
  323.             }
  324.             // Cascaded W-lock must be allowed
  325.             if (w_cycle % 8 == 0) {
  326.                 assert(m_RW->TryWriteLock());
  327.                 m_Res->BeginWrite(m_Index);
  328.             }
  329.             // Cascaded R-lock must be allowed
  330.             if (w_cycle % 10 == 0) {
  331.                 assert(m_RW->TryReadLock());
  332.                 m_Res->BeginRead(m_Index);
  333.             }
  334.             // ======= CTls test =======
  335.             // Verify TLS - current value must be 10
  336.             assert(*m_Tls->GetValue() == 10);
  337.             // Continue CRWLock test
  338.             for (int i=0; i<7; i++) {
  339.                 delay(1);
  340.                 s_var++;
  341.             }
  342.             if (w_cycle % 4 == 0) {
  343.                 m_Res->EndWrite(m_Index);
  344.                 m_RW->Unlock();
  345.             }
  346.             if (w_cycle % 6 == 0) {
  347.                 m_Res->EndRead(m_Index);
  348.                 m_RW->Unlock();
  349.             }
  350.             if (w_cycle % 8 == 0) {
  351.                 m_Res->EndWrite(m_Index);
  352.                 m_RW->Unlock();
  353.             }
  354.             if (w_cycle % 10 == 0) {
  355.                 m_Res->EndRead(m_Index);
  356.                 m_RW->Unlock();
  357.             }
  358.             m_Res->EndWrite(m_Index);
  359.             m_RW->Unlock();
  360.             delay(1);
  361.         }
  362.     }
  363.     // ======= CTls test =======
  364.     // Verify TLS - current value must be 10
  365.     assert(*m_Tls->GetValue() == 10);
  366.     for (int i=0; i<5; i++) {
  367.         stored_value = new int;
  368.         assert(stored_value != 0);
  369.         *stored_value = *m_Tls->GetValue()+1;
  370.         m_Tls->SetValue(stored_value,
  371.                         TestTlsCleanup, &m_CheckValue);
  372.         assert(*stored_value == m_CheckValue+1);
  373.     }
  374.     assert(*m_Tls->GetValue() == 15);
  375.     assert(m_CheckValue == 14);
  376.     // ======= CThread::Detach() and CThread::Join() test =======
  377.     if (m_Index % 2 == 0) {
  378.         CMutexGuard exit_guard(*exit_locks[m_Index]);
  379.         delay(10); // Provide delay for join-before-exit
  380.     }
  381.     if (m_Index % 3 == 0)
  382.     {
  383.         // Never verified, since CThread::Exit() terminates the thread
  384.         // inside Test_CThreadExit().
  385.         assert(Test_CThreadExit());
  386.     }
  387.     return reinterpret_cast<void*>(-1);
  388. }
  389. /////////////////////////////////////////////////////////////////////////////
  390. //  Test application
  391. class CThreadedApp : public CNcbiApplication
  392. {
  393.     void Init(void);
  394.     int Run(void);
  395. };
  396. void CThreadedApp::Init(void)
  397. {
  398.     // Prepare command line descriptions
  399.     auto_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
  400.     // sNumThreads
  401.     arg_desc->AddDefaultKey
  402.         ("threads", "NumThreads",
  403.          "Total number of threads to create and run",
  404.          CArgDescriptions::eInteger, NStr::IntToString(sNumThreads));
  405.     arg_desc->SetConstraint
  406.         ("threads", new CArgAllow_Integers(cNumThreadsMin, cNumThreadsMax));
  407.     // sSpawnBy
  408.     arg_desc->AddDefaultKey
  409.         ("spawnby", "SpawnBy",
  410.          "Threads spawning factor",
  411.          CArgDescriptions::eInteger, NStr::IntToString(sSpawnBy));
  412.     arg_desc->SetConstraint
  413.         ("spawnby", new CArgAllow_Integers(cSpawnByMin, cSpawnByMax));
  414.     // sNumRCycles
  415.     arg_desc->AddDefaultKey
  416.         ("rcycles", "RCycles",
  417.          "Number of read cycles by each reader thread",
  418.          CArgDescriptions::eInteger, NStr::IntToString(sRCycles));
  419.     arg_desc->SetConstraint
  420.         ("rcycles", new CArgAllow_Integers(cRCyclesMin, cRCyclesMax));
  421.     // sNumWCycles
  422.     arg_desc->AddDefaultKey
  423.         ("wcycles", "WCycles",
  424.          "Number of write cycles by each writer thread",
  425.          CArgDescriptions::eInteger, NStr::IntToString(sWCycles));
  426.     arg_desc->SetConstraint
  427.         ("wcycles", new CArgAllow_Integers(cWCyclesMin, cWCyclesMax));
  428.     string prog_description =
  429.         "This is a program testing thread, TLS, mutex and RW-lock classes.";
  430.     arg_desc->SetUsageContext(GetArguments().GetProgramBasename(),
  431.                               prog_description, false);
  432.     SetupArgDescriptions(arg_desc.release());
  433. }
  434. int CThreadedApp::Run(void)
  435. {
  436. # if defined(NCBI_POSIX_THREADS)
  437.     NcbiCout << "OS: Unix" << NcbiEndl;
  438. # elif defined(NCBI_WIN32_THREADS)
  439.     NcbiCout << "OS: MS-Windows" << NcbiEndl;
  440. # else
  441.     NcbiCout << "OS: unknown" << NcbiEndl;
  442. # endif
  443.     // Process command line
  444.     const CArgs& args = GetArgs();
  445.     sNumThreads = args["threads"].AsInteger();
  446.     sSpawnBy    = args["spawnby"].AsInteger();
  447.     sRCycles    = args["rcycles"].AsInteger();
  448.     sWCycles    = args["wcycles"].AsInteger();
  449.     NcbiCout << "Test parameters:" << NcbiEndl;
  450.     NcbiCout << "tTotal threads     " << sNumThreads << NcbiEndl;
  451.     NcbiCout << "tSpawn threads by  " << sSpawnBy << NcbiEndl;
  452.     NcbiCout << "tR-cycles          " << sRCycles << NcbiEndl;
  453.     NcbiCout << "tW-cycles          " << sWCycles << NcbiEndl << NcbiEndl;
  454.     // Redirect error log to hide messages sent by delay()
  455.     SetDiagStream(0);
  456.     // Test CBaseTls::Discard()
  457.     NcbiCout << "Creating/discarding TLS test...";
  458.     int main_cleanup_flag = 0;
  459.     CTls<int>* dummy_tls = new CTls<int>;
  460.     assert(main_cleanup_flag == 0);
  461.     dummy_tls->SetValue(&main_cleanup_flag, Main_Thread_Tls_Cleanup);
  462.     assert(main_cleanup_flag == 0);
  463.     dummy_tls->Discard();
  464.     assert(main_cleanup_flag == 1);
  465.     NcbiCout << " Passed" << NcbiEndl << NcbiEndl;
  466.     // Create test objects
  467.     main_cleanup_flag = 0;
  468.     CRef< CTls<int> > tls(new CTls<int>);
  469.     tls->SetValue(0);
  470.     CRWLock rw;
  471.     CSharedResource res;
  472.     {{
  473.         CFastMutexGuard guard(s_GlobalLock);
  474.         NcbiCout << "===== Starting threads =====" << NcbiEndl;
  475.     }}
  476.     // Prepare exit-locks, lock each 2nd mutex
  477.     // They will be used by join/detach before exit
  478.     for (int i=0; i<sNumThreads; i++) {
  479.         states[i] = eNull;
  480.         exit_locks[i] = new CMutex;
  481.         if (i % 2 == 0) {
  482.             exit_locks[i]->Lock();
  483.         }
  484.     }
  485.     // Create and run threads
  486.     for (int i=0; i<sSpawnBy; i++) {
  487.         int idx;
  488.         {{
  489.             CFastMutexGuard spawn_guard(s_GlobalLock);
  490.             if (s_NextIndex >= sNumThreads) {
  491.                 break;
  492.             }
  493.             idx = s_NextIndex;
  494.             s_NextIndex++;
  495.         }}
  496.         // Check Discard() for some threads
  497.         if (i % 2 == 0) {
  498.             thr[idx] = new CTestThread(idx, tls, &rw, &res);
  499.             assert(states[idx] == eCreated);
  500.             thr[idx]->Discard();
  501.             assert(states[idx] == eDestroyed);
  502.         }
  503.         
  504.         thr[idx] = new CTestThread(idx, tls, &rw, &res);
  505.         assert(states[idx] == eCreated);
  506.         thr[idx]->Run();
  507.         {{
  508.             CFastMutexGuard guard(s_GlobalLock);
  509.             NcbiCout << idx << " ";
  510.         }}
  511.     }
  512.     // Wait for all threads running
  513.     {{
  514.         CFastMutexGuard guard(s_GlobalLock);
  515.         NcbiCout << NcbiEndl << NcbiEndl <<
  516.                     "===== Waiting for all threads to run =====" << NcbiEndl;
  517.     }}
  518.     map<int, bool> thread_map;
  519.     for (int i=0; i<sNumThreads; i++) {
  520.         thread_map[i] = false;
  521.     }
  522.     int ready = 0;
  523.     while (ready < sNumThreads) {
  524.         ready = 0;
  525.         for (int i=0; i<sNumThreads; i++) {
  526.             if (states[i] >= eRunning) {
  527.                 ready++;
  528.                 if ( !thread_map[i] ) {
  529.                     CFastMutexGuard guard(s_GlobalLock);
  530.                     NcbiCout << i << " ";
  531.                     thread_map[i] = true;
  532.                 }
  533.             }
  534.         }
  535.     }
  536.     {{
  537.         CFastMutexGuard guard(s_GlobalLock);
  538.         NcbiCout << NcbiEndl << NcbiEndl <<
  539.                     "===== Joining threads before exit =====" << NcbiEndl;
  540.     }}
  541.     for (int i=0; i<sNumThreads; i++) {
  542.         // Try to join before exit
  543.         if (i % 4 == 2) {
  544.             assert(states[i] < eTerminated);
  545.             exit_locks[i]->Unlock();
  546.             void* exit_data = 0;
  547.             thr[i]->Join(&exit_data);
  548.             // Must be set to 1 by Main()
  549.             assert(exit_data != 0);
  550.             {{
  551.                 CFastMutexGuard guard(s_GlobalLock);
  552.                 NcbiCout << i << " ";
  553.             }}
  554.         }
  555.     }
  556.     // Reset CRef to the test tls. One more CRef to the object
  557.     // must have been stored in the CThread's m_UsedTlsSet.
  558.     assert(main_cleanup_flag == 0);
  559.     tls.Reset();
  560.     assert(main_cleanup_flag == 0);
  561.     {{
  562.         CFastMutexGuard guard(s_GlobalLock);
  563.         NcbiCout << NcbiEndl << NcbiEndl <<
  564.                     "===== Detaching threads before exit =====" << NcbiEndl;
  565.     }}
  566.     for (int i=0; i<sNumThreads; i++) {
  567.         // Detach before exit
  568.         if (i % 4 == 0) {
  569.             assert(states[i] < eTerminated);
  570.             thr[i]->Detach();
  571.             exit_locks[i]->Unlock();
  572.             {{
  573.                 CFastMutexGuard guard(s_GlobalLock);
  574.                 NcbiCout << i << " ";
  575.             }}
  576.         }
  577.     }
  578.     // Wait for all threads to exit
  579.     delay(10);
  580.     {{
  581.         CFastMutexGuard guard(s_GlobalLock);
  582.         NcbiCout << NcbiEndl << NcbiEndl <<
  583.                     "===== Detaching threads after exit =====" << NcbiEndl;
  584.     }}
  585.     for (int i=0; i<sNumThreads; i++) {
  586.         // Detach after exit
  587.         if (i % 4 == 1) {
  588.             assert(states[i] != eDestroyed);
  589.             thr[i]->Detach();
  590.             {{
  591.                 CFastMutexGuard guard(s_GlobalLock);
  592.                 NcbiCout << i << " ";
  593.             }}
  594.         }
  595.     }
  596.     {{
  597.         CFastMutexGuard guard(s_GlobalLock);
  598.         NcbiCout << NcbiEndl << NcbiEndl <<
  599.                     "===== Joining threads after exit =====" << NcbiEndl;
  600.     }}
  601.     for (int i=0; i<sNumThreads; i++) {
  602.         // Join after exit
  603.         if (i % 4 == 3) {
  604.             assert(states[i] != eDestroyed);
  605.             thr[i]->Join();
  606.             {{
  607.                 CFastMutexGuard guard(s_GlobalLock);
  608.                 NcbiCout << i << " ";
  609.             }}
  610.         }
  611.     }
  612.     // Wait for all threads to be destroyed
  613.     {{
  614.         CFastMutexGuard guard(s_GlobalLock);
  615.         NcbiCout << NcbiEndl << NcbiEndl <<
  616.                     "===== Waiting for all threads to be destroyed =====" << NcbiEndl;
  617.     }}
  618.     for (int i=0; i<sNumThreads; i++) {
  619.         thread_map[i] = false;
  620.     }
  621.     ready = 0;
  622.     while (ready < sNumThreads) {
  623.         ready = 0;
  624.         for (int i=0; i<sNumThreads; i++) {
  625.             if (states[i] == eDestroyed) {
  626.                 ready++;
  627.                 if ( !thread_map[i] ) {
  628.                     CFastMutexGuard guard(s_GlobalLock);
  629.                     NcbiCout << i << " ";
  630.                     thread_map[i] = true;
  631.                     delete exit_locks[i];
  632.                 }
  633.             }
  634.         }
  635.     }
  636.     {{
  637.         CFastMutexGuard guard(s_GlobalLock);
  638.         NcbiCout << NcbiEndl << NcbiEndl << "Test passed" << NcbiEndl;
  639.     }}
  640.     return 0;
  641. }
  642. /////////////////////////////////////////////////////////////////////////////
  643. //  MAIN
  644. int main(int argc, const char* argv[]) 
  645. {
  646.     CThreadedApp app;
  647.     return app.AppMain(argc, argv, 0, eDS_Default, 0);
  648. }
  649. /*
  650.  * ===========================================================================
  651.  * $Log: test_ncbithr.cpp,v $
  652.  * Revision 1000.1  2004/06/01 19:10:21  gouriano
  653.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.7
  654.  *
  655.  * Revision 6.7  2004/05/14 13:59:51  gorelenk
  656.  * Added include of ncbi_pch.hpp
  657.  *
  658.  * Revision 6.6  2002/11/04 21:29:05  grichenk
  659.  * Fixed usage of const CRef<> and CRef<> constructor
  660.  *
  661.  * Revision 6.5  2002/09/19 20:05:43  vasilche
  662.  * Safe initialization of static mutexes
  663.  *
  664.  * Revision 6.4  2002/04/16 18:49:09  ivanov
  665.  * Centralize threatment of assert() in tests.
  666.  * Added #include <test/test_assert.h>. CVS log moved to end of file.
  667.  *
  668.  * Revision 6.3  2002/03/13 05:02:09  vakatov
  669.  * sNumThreads = 35;  sSpawnBy = 6;
  670.  *
  671.  * Revision 6.2  2001/04/03 18:21:23  grichenk
  672.  * + test for CThread::Exit()
  673.  *
  674.  * Revision 6.1  2001/03/13 22:45:20  vakatov
  675.  * Initial revision
  676.  *
  677.  * ===========================================================================
  678.  */