📄 thread.cpp
字号:
/******************************************************************************** thread.cpp: thread management*-------------------------------------------------------------------------------* (c)1999-2001 VideoLAN* $Id: thread.cpp,v 1.7 2002/07/12 18:09:36 massiot Exp $** Authors: Benoit Steiner <benny@via.ecp.fr>** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version 2* of the License, or (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.**------------------------------------------------------------------------------*********************************************************************************///------------------------------------------------------------------------------// Preamble//------------------------------------------------------------------------------#include "defs.h"#ifdef PTHREAD_COND_T_IN_PTHREAD_H#include <pthread.h>#include <semaphore.h>#include <errno.h>#elif defined WIN32#include <windows.h>#include <process.h>#endif#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "common.h"#include "string.h"#include "system.h"#include "exception.h"#include "list.h"#include "thread.h"#include "debug.h"#include "list.cpp"#define INT_TEST_COUNT 15 // Test count before calling interruption // process#define INT_TEST_DELAY 1000000 // Delay in microseconds between each test // before calling interruption process//******************************************************************************// Class C_ThreadKiller//******************************************************************************////******************************************************************************/*//------------------------------------------------------------------------------// //------------------------------------------------------------------------------class C_ThreadKiller{public: // The thread is created detachable during the application startup. It will // live until the end of the program C_ThreadKiller(); ~C_ThreadKiller(); void Kill(C_Thread* pThread);protected: // Main loop static void* MainLoop(void* pThread);private: bool m_bStop;#ifdef PTHREAD_COND_T_IN_PTHREAD_H pthread_t tId;#elif defined WIN32 HANDLE hThread; WORD dwId;#endif E_Exception* m_pException; C_Thread* m_pThread; C_Mutex m_cLock; C_Semaphore m_cJobAvailable; C_Semaphore m_cJobDone;};//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_ThreadKiller::C_ThreadKiller() : m_cJobAvailable(0), m_cJobDone(0){ m_bStop = false; m_pException = NULL; m_pThread = NULL; pthread_attr_t sAttr; pthread_attr_init(&sAttr); pthread_attr_setdetachstate(&sAttr, PTHREAD_CREATE_DETACHED); int iRc = pthread_create(&tId, NULL, C_ThreadKiller::MainLoop, this); pthread_attr_destroy(&sAttr); ASSERT(!iRc);}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_ThreadKiller::~C_ThreadKiller(){ m_bStop = true; // End of the main loop. No need to lock because all threads must be // destroyed at this point of the execution. m_pThread = NULL; m_cJobAvailable.Post(); // Cleaning void* pRc = NULL; int iRc = pthread_join(tId, &pRc); ASSERT(!iRc); ASSERT(!pRc);}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void* C_ThreadKiller::MainLoop(void* pThread){ C_ThreadKiller* pThis = (C_ThreadKiller*)pThread; while(!pThis->m_bStop) { // Wait for something to do pThis->m_cJobAvailable.Wait(); // Do the job if(pThis->m_pThread) { // Handle the request try { pThis->m_pThread->Stop(); } catch(E_Exception e) { pThis->m_pException = new E_Exception(e); } pThis->m_cJobDone.Post(); } else ASSERT(pThis->m_bStop); } return NULL;}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_ThreadKiller::Kill(C_Thread* pThread){ ASSERT(pThread); // Only one thread can be killed at a time for now m_cLock.Lock(); // Process the request m_pThread = pThread; m_cJobAvailable.Post(); m_cJobDone.Wait(); // Get the exception if there was one if(m_pException) { E_Exception e(*m_pException); delete m_pException; m_pException = NULL; m_cLock.UnLock(); throw e; } else m_cLock.UnLock();}*///******************************************************************************// Class C_Thread//******************************************************************************////******************************************************************************//------------------------------------------------------------------------------// Instanciation of the static list of running threads and of the thread killer//------------------------------------------------------------------------------C_List<C_Thread> C_Thread::s_cThreadList;//C_ThreadKiller s_cThreadKiller;//------------------------------------------------------------------------------////------------------------------------------------------------------------------C_Thread::C_Thread(unsigned int iProperties){ m_iFlags = iProperties; m_iStatus = THREAD_STATUS_NOTSTARTED;#ifdef PTHREAD_COND_T_IN_PTHREAD_H ZERO(tId);#elif defined WIN32 ZERO(hThread); ZERO(dwId);#endif}//------------------------------------------------------------------------------////------------------------------------------------------------------------------C_Thread::~C_Thread(){ // Verify that the thread has been stopped before ASSERT(s_cThreadList.Find(*this) < 0);}//------------------------------------------------------------------------------////------------------------------------------------------------------------------void C_Thread::Create(){ try { // Do some initialisations before starting the real job InitWork(); // Now launch the thread#ifdef PTHREAD_COND_T_IN_PTHREAD_H // Set the thread attributes. It is important for the thread to be created // joinable unless the instance of the class could be destroyed before the // end of the execution of DoWork pthread_attr_t sAttr; pthread_attr_init(&sAttr); pthread_attr_setdetachstate(&sAttr, PTHREAD_CREATE_JOINABLE); int iRc = pthread_create(&tId, NULL, C_Thread::StartRoutine, this); pthread_attr_destroy(&sAttr); #elif defined _WIN32 unsigned long threadID; hThread = (HANDLE)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)C_Thread::StartRoutine, this, 0, &threadID); int iRc = ( hThread ? 0 : 1 );#endif if(iRc) { throw E_Exception(GEN_ERR, "Unable to start thread: " + GetErrorMsg()); } // Reference the thread in the list of running threads s_cThreadList.PushEnd(this); } catch(E_Exception e) { throw E_Exception(GEN_ERR, "Unable to create thread", e); }}//------------------------------------------------------------------------------////------------------------------------------------------------------------------void C_Thread::Cancel(){ try { // Ask for thread cancellation#ifdef PTHREAD_COND_T_IN_PTHREAD_H int iRc = pthread_cancel(tId);#elif defined WIN32 int iRc = 0;#endif if(iRc) throw E_Exception(iRc, "Thread cancellation failed: " + GetErrorMsg()); // Now Stop the cancelled thread Stop(); } catch(E_Exception e) { throw E_Exception(GEN_ERR, "Error when cancelling thread", e); }}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Thread::Stop(){ try { // As all our threads are created joinable, we must ensure that the calling // thread is a different thread to avoid a deadlock. So if a thread try to stop // itself, we ask another thread (the killer) to do the job.
#ifdef PTHREAD_COND_T_IN_PTHREAD_H if(pthread_self() == tId)#else if (GetCurrentThread() == hThread)#endif { ASSERT(false); //s_cThreadKiller.Kill(this); } // Don't join if not started // It avoids exception's generation because pthread_join returns an error // when the thread was not started. else if(m_iStatus != THREAD_STATUS_NOTSTARTED) { // Ask the user work routine to stop its normal processing StopWork(); // Try to join the thread in order to clean the resources it used and // to synchronise the calling thread with the destruction of this thread // Seems that there is a bug here in the libpthread: when the thread // is cancelled, pRc is set to any value so that there is no way to get // the return value of the DoWork method // Ok, let's try again to see if the pb still occurs E_Exception* p_eError = NULL;#ifdef PTHREAD_COND_T_IN_PTHREAD_H int iRc = pthread_join(tId, (void**)&p_eError);#elif defined _WIN32 int iRc = 0; WaitForSingleObject (hThread, INFINITE);#endif if(iRc) { // Look at thre return code of the joined thread ASSERT(p_eError); E_Exception e(*p_eError); delete p_eError; throw e; } // Cleaning CleanWork(); // Remove the thread from the list of running thread, but only if it has been // successfully stopped. Do not delete it, this is the responsability of the // user int iThreadPos = s_cThreadList.Find(*this); ASSERT(iThreadPos >= 0); s_cThreadList.Remove(iThreadPos); } } catch(E_Exception e) { throw E_Exception(GEN_ERR, "Unable to stop thread", e); }}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Thread::Interrupt(){#ifdef PTHREAD_COND_T_IN_PTHREAD_H int iRc = pthread_cancel(tId);#elif defined _WIN32 int iRc = 0;#endif if(iRc) throw E_Exception(GEN_ERR, "Unable to interrupt thread: " + GetErrorMsg()); m_iStatus = THREAD_STATUS_INTERRUPTED;}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Thread::DelayedInterruption(){ if(m_iStatus == THREAD_STATUS_STARTED) { for(unsigned int ui = 0; (ui < INT_TEST_COUNT) && (m_iStatus == THREAD_STATUS_STARTED); ui++) {#ifdef WIN32 Sleep(INT_TEST_DELAY / 1000000);#else usleep(INT_TEST_DELAY);#endif } } if(m_iStatus == THREAD_STATUS_STARTED) { printf("Thread not stopped after %u s," " calling interruption process\n", INT_TEST_COUNT * INT_TEST_DELAY / 1000000); Interrupt(); }}//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -