📄 ncbithr.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbithr.cpp,v $ * PRODUCTION Revision 1000.1 2004/06/01 19:09:26 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.30 * PRODUCTION * =========================================================================== *//* $Id: ncbithr.cpp,v 1000.1 2004/06/01 19:09:26 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: Denis Vakatov, Aleksey Grichenko * * File Description: * Multi-threading -- classes, functions, and features. * * TLS: * CTlsBase -- TLS implementation (base class for CTls<>) * * THREAD: * CThread -- thread wrapper class * * RW-LOCK: * CInternalRWLock -- platform-dependent RW-lock structure (fwd-decl) * CRWLock -- Read/Write lock related data and methods * */#include <ncbi_pch.hpp>#include <corelib/ncbithr.hpp>#include <corelib/ncbimtx.hpp>#include <corelib/ncbi_safe_static.hpp>#include <corelib/ncbi_limits.h>#include <corelib/ncbi_system.hpp>#include <assert.h>#ifdef NCBI_POSIX_THREADS# include <sys/time.h> // for gettimeofday()#endif#include "ncbidbg_p.hpp"BEGIN_NCBI_SCOPE/////////////////////////////////////////////////////////////////////////////// CTlsBase:://// Flag and function to report s_Tls_TlsSet destructionstatic bool s_TlsSetDestroyed = false;static void s_TlsSetCleanup(void* /* ptr */){ s_TlsSetDestroyed = true;}// Set of all TLS objects -- to prevent memory leaks due to// undestroyed TLS objects, and to avoid premature TLS destruction.typedef set< CRef<CTlsBase> > TTls_TlsSet;static CSafeStaticPtr<TTls_TlsSet> s_Tls_TlsSet(s_TlsSetCleanup);// Protects "s_Tls_TlsSet"struct S { DECLARE_CLASS_STATIC_FAST_MUTEX(s_TlsMutex0);};DEFINE_CLASS_STATIC_FAST_MUTEX(S::s_TlsMutex0);#define s_TlsMutex S::s_TlsMutex0CTlsBase::CTlsBase(void){ DoDeleteThisObject(); // Create platform-dependent TLS key (index)#if defined(NCBI_WIN32_THREADS) xncbi_Verify((m_Key = TlsAlloc()) != DWORD(-1));#elif defined(NCBI_POSIX_THREADS) xncbi_Verify(pthread_key_create(&m_Key, 0) == 0);#else m_Key = 0;#endif m_Initialized = true; // Add to the cleanup set if it still exists if ( !s_TlsSetDestroyed ) { CFastMutexGuard guard(s_TlsMutex); s_Tls_TlsSet->insert(CRef<CTlsBase> (this)); }}CTlsBase::~CTlsBase(void){ x_Reset(); m_Initialized = false; // Destroy system TLS key#if defined(NCBI_WIN32_THREADS) if ( TlsFree(m_Key) ) { m_Key = 0; return; } assert(0);#elif defined(NCBI_POSIX_THREADS) if (pthread_key_delete(m_Key) == 0) { m_Key = 0; return; } assert(0);#else m_Key = 0; return;#endif}void CTlsBase::x_Discard(void){ if ( s_TlsSetDestroyed ) { return; // Nothing to do - the TLS set has been destroyed } CFastMutexGuard guard(s_TlsMutex); NON_CONST_ITERATE(TTls_TlsSet, it, *s_Tls_TlsSet) { if (it->GetPointer() == this) { s_Tls_TlsSet->erase(it); break; } }}// Platform-specific TLS data storinginlinevoid s_TlsSetValue(TTlsKey& key, void* data, const char* err_message){#if defined(NCBI_WIN32_THREADS) xncbi_Validate(TlsSetValue(key, data), err_message);#elif defined(NCBI_POSIX_THREADS) xncbi_Validate(pthread_setspecific(key, data) == 0, err_message);#else key = data; assert(err_message); // to get rid of the "unused variable" warning#endif}void CTlsBase::x_SetValue(void* value, FCleanupBase cleanup, void* cleanup_data){ if ( !m_Initialized ) { return; } // Get previously stored data STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData()); // Create and initialize TLS structure, if it was not present if ( !tls_data ) { tls_data = new STlsData; xncbi_Validate(tls_data != 0, "CTlsBase::x_SetValue() -- cannot allocate " "memory for TLS data"); tls_data->m_Value = 0; tls_data->m_CleanupFunc = 0; tls_data->m_CleanupData = 0; } // Cleanup if (tls_data->m_CleanupFunc && tls_data->m_Value != value) { tls_data->m_CleanupFunc(tls_data->m_Value, tls_data->m_CleanupData); } // Store the values tls_data->m_Value = value; tls_data->m_CleanupFunc = cleanup; tls_data->m_CleanupData = cleanup_data; // Store the structure in the TLS s_TlsSetValue(m_Key, tls_data, "CTlsBase::x_SetValue() -- error setting value"); // Add to the used TLS list to cleanup data in the thread Exit() CThread::AddUsedTls(this);}void CTlsBase::x_Reset(void){ if ( !m_Initialized ) { return; } // Get previously stored data STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData()); if ( !tls_data ) { return; } // Cleanup & destroy if ( tls_data->m_CleanupFunc ) { tls_data->m_CleanupFunc(tls_data->m_Value, tls_data->m_CleanupData); } delete tls_data; // Store NULL in the TLS s_TlsSetValue(m_Key, 0, "CTlsBase::x_Reset() -- error cleaning-up TLS");}/////////////////////////////////////////////////////////////////////////////// CExitThreadException:://// Exception used to terminate threads safely, cleaning up// all the resources allocated.//class CExitThreadException{public: // Create new exception object, initialize counter. CExitThreadException(void); // Create a copy of exception object, increase counter. CExitThreadException(const CExitThreadException& prev); // Destroy the object, decrease counter. If the counter is // zero outside of CThread::Wrapper(), rethrow exception. ~CExitThreadException(void); // Inform the object it has reached CThread::Wrapper(). void EnterWrapper(void) { *m_InWrapper = true; }private: int* m_RefCount; bool* m_InWrapper;};CExitThreadException::CExitThreadException(void) : m_RefCount(new int), m_InWrapper(new bool){ *m_RefCount = 1; *m_InWrapper = false;}CExitThreadException::CExitThreadException(const CExitThreadException& prev) : m_RefCount(prev.m_RefCount), m_InWrapper(prev.m_InWrapper){ (*m_RefCount)++;}CExitThreadException::~CExitThreadException(void){ if (--(*m_RefCount) > 0) { // Not the last object - continue to handle exceptions return; } bool tmp_in_wrapper = *m_InWrapper; // save the flag delete m_RefCount; delete m_InWrapper; if ( !tmp_in_wrapper ) { // Something is wrong - terminate the thread assert(((void)("CThread::Exit() -- cannot exit thread"), 0));#if defined(NCBI_WIN32_THREADS) ExitThread(0);#elif defined(NCBI_POSIX_THREADS) pthread_exit(0);#endif }}/////////////////////////////////////////////////////////////////////////////// CThread:://// Mutex to protect CThread members and to make sure that Wrapper() function// will not proceed until after the appropriate Run() is finished.DEFINE_STATIC_FAST_MUTEX(s_ThreadMutex);DEFINE_STATIC_FAST_MUTEX(s_TlsCleanupMutex);// Internal storage for thread objects and related variables/functionsCTls<CThread>* CThread::sm_ThreadsTls;void s_CleanupThreadsTls(void* /* ptr */){ CThread::sm_ThreadsTls = 0; // Indicate that the TLS is destroyed}void CThread::CreateThreadsTls(void){ static CSafeStaticRef< CTls<CThread> > s_ThreadsTlsRef(s_CleanupThreadsTls); sm_ThreadsTls = &s_ThreadsTlsRef.Get();}TWrapperRes CThread::Wrapper(TWrapperArg arg){ // Get thread object and self ID CThread* thread_obj = static_cast<CThread*>(arg); // Set Toolkit thread ID. Otherwise no mutexes will work! {{ CFastMutexGuard guard(s_ThreadMutex); static int s_ThreadCount = 0; s_ThreadCount++; thread_obj->m_ID = s_ThreadCount; xncbi_Validate(thread_obj->m_ID != 0, "CThread::Wrapper() -- error assigning thread ID"); GetThreadsTls().SetValue(thread_obj); }} // Run user-provided thread main function here try { thread_obj->m_ExitData = thread_obj->Main(); } catch (CExitThreadException& e) { e.EnterWrapper(); } STD_CATCH_ALL("CThread::Wrapper: CThread::Main() failed"); // Call user-provided OnExit() try { thread_obj->OnExit(); } STD_CATCH_ALL("CThread::Wrapper: CThread::OnExit() failed"); // Cleanup local storages used by this thread {{ CFastMutexGuard tls_cleanup_guard(s_TlsCleanupMutex); NON_CONST_ITERATE(TTlsSet, it, thread_obj->m_UsedTls) { CRef<CTlsBase> tls = *it; tls->x_Reset(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -