在 《利用ACL庫開發高併發半駐留式線程池程序》 中介紹瞭如何使用 C 版本的 acl 線程庫編寫多線程程序,本文將會介紹如何使用 C++ 版本的 acl 線程庫編寫多線程程序,雖然 C++ 版 acl 線程庫基於 C 版的線程庫,但卻提供了更爲清晰簡潔的接口定義(不少地方參考了 JAVA 的線程接口定義)。下面是一個簡單的使用線程的例子:git
#include "acl_cpp/lib_acl.hpp" ////////////////////////////////////////////////////////////////////////// // 子線程類定義 class mythread : public acl::thread { public: mythread() {} ~mythread() {} protected: // 基類純虛函數,當在主線程中調用線程實例的 start 函數時 // 該虛函數將會被調用 virtual void* run() { const char* myname = "run"; printf("%s: thread id: %lu, %lu\r\n", myname, thread_id(), acl::thread::thread_self()); return NULL; } }; ////////////////////////////////////////////////////////////////////////// static void test_thread(void) { const char* myname = "test_thread"; mythread thr; // 子線程對象實例 // 設置線程的屬性爲非分離方式,以便於下面能夠調用 wait // 等待線程結束 thr.set_detachable(false); // 啓動一個子線程 if (thr.start() == false) { printf("start thread failed\r\n"); return; } printf("%s: thread id is %lu, main thread id: %lu\r\n", myname, thr.thread_id(), acl::thread::thread_self()); // 等待子線程運行結束 if (thr.wait(NULL) == false) printf("wait thread failed\r\n"); else printf("wait thread ok\r\n"); } int main(void) { // 初始化 acl 庫 acl::acl_cpp_init(); test_thread(); #ifdef WIN32 printf("enter any key to exit ...\r\n"); getchar(); #endif return 0; }
從上面的示例來看,使用 acl 的線程庫建立使用線程仍是很是簡單的。打開 lib_acl_cpp/include/acl_cpp/stdlib/thread.hpp 文件,能夠看到線程類的聲明,其中有兩個基類:acl::thread 與 acl::thread_job,在 基類 acl::thread_job 中有一個純虛函數 run(),acl::thread 也繼承自 acl::thread_job,用戶的線程類須要繼承 acl::thread,而且須要實現基類 acl::thread_job 的純虛函數: run()。當應用在主線程中調用線程實例的 start() 函數時,acl 線程庫內部便建立一個子線程,子線程被建立後線程對象的 run() 函數便被調用。下面是 acl::thread 類中幾個主要的方法定義:程序員
class thread_job { public: thread_job() {} virtual ~thread_job() {} /** * 純虛函數,子類必須實現此函數,該函數在子線程中執行 * @return {void*} 線程退出前返回的參數 */ virtual void* run() = 0; }; class thread : public thread_job { public: thread(); virtual ~thread(); /** * 開始啓動線程過程,一旦該函數被調用,則會當即啓動一個新的 * 子線程,在子線程中執行基類 thread_job::run 過程 * @return {bool} 是否成功建立線程 */ bool start(); /** * 當建立線程時爲非 detachable 狀態,則能夠調用此函數 * 等待線程結束;不然,若建立線程時爲 detachable 狀態 * 在調用本函數時將會報錯 * @param out {void**} 當該參數非空指針時,該參數用來存放 * 線程退出前返回的參數 * @return {bool} 是否成功 */ bool wait(void** out = NULL); /** * 在調用 start 前調用此函數能夠設置所建立線程是否爲 * 分離 (detachable) 狀態;若是未調用此函數,則所建立 * 的線程默認爲分離狀態 * @param yes {bool} 是否爲分離狀態 * @return {thread&} */ thread& set_detachable(bool yes); /** * 在調用 start 前調用此函數能夠設置所建立線程的堆棧大小 * @param size {size_t} 線程堆棧大小,當該值爲 0 或未 * 調用此函數,則所建立的線程堆棧大小爲系統的默認值 * @return {thread&} */ thread& set_stacksize(size_t size); /** * 在調用 start 後調用此函數能夠得到所建立線程的 id 號 * @return {unsigned long} */ unsigned long thread_id() const; /** * 當前調用者所在線程的線程 id 號 * @return {unsigned long} */ static unsigned long thread_self(); .... };
從上面的線程示例及 acl::thread 的類定義,也許有人會以爲應該把 acl::thread_job 的純虛方法:run() 放在 acl::thread 類中,甚至以爲 acl::thread_job 類是多餘的,可是由於 acl 庫中還支持線程池方式,則 acl::thread_job 就顯得頗有必要了。在 lib_acl_cpp\include\acl_cpp\stdlib\thread_pool.hpp 頭文件中能夠看到 acl 的線程池類 acl::thread_pool 的聲明,該類的主要函數接口以下:github
class thread_pool { /** * 啓動線程池,在建立線程池對象後,必須首先調用此函數以啓動線程池 */ void start(); /** * 中止並銷燬線程池,並釋放線程池資源,調用此函數可使全部子線程退出, * 但並不釋放本實例,若是該類實例是動態分配的則用戶應該自釋放類實例, * 在調用本函數後,若是想重啓線程池過程,則必須從新調用 start 過程 */ void stop(); /** * 等待線程池中的全部線程池執行完全部任務 */ void wait(); /** * 將一個任務交給線程池中的一個線程去執行,線程池中的 * 線程會執行該任務中的 run 函數 * @param job {thread_job*} 線程任務 * @return {bool} 是否成功 */ bool run(thread_job* job); /** * 將一個任務交給線程池中的一個線程去執行,線程池中的 * 線程會執行該任務中的 run 函數;該函數功能與 run 功能徹底相同,只是爲了 * 使 JAVA 程序員看起來更爲熟悉才提供了此接口 * @param job {thread_job*} 線程任務 * @return {bool} 是否成功 */ bool execute(thread_job* job); /** * 在調用 start 前調用此函數能夠設置所建立線程的堆棧大小 * @param size {size_t} 線程堆棧大小,當該值爲 0 或未 * 調用此函數,則所建立的線程堆棧大小爲系統的默認值 * @return {thread&} */ thread_pool& set_stacksize(size_t size); /** * 設置線程池最大線程個數限制 * @param max {size_t} 最大線程數,若是不調用此函數,則內部缺省值爲 100 * @return {thread_pool&} */ thread_pool& set_limit(size_t max); /** * 設置線程池中空閒線程的超時退出時間 * @param ttl {int} 空閒超時時間(秒),若是不調用此函數,則內部缺省爲 0 * @return {thread_pool&} */ thread_pool& set_idle(int ttl); ...... };
這些接口定義也相對簡單,下面給出一個使用線程池的例子:多線程
// 線程工做類 class myjob : public acl::thread_job { public: myjob() {} myjob() {} protected: // 基類中的純虛函數 virtual void* run() { const char* myname = "run"; printf("%s: thread id: %lu\r\n", myname, acl::thread::thread_self()); return NULL; } }; ////////////////////////////////////////////////////////////////////////// // 線程池類 class mythread_pool : public acl::thread_pool { public: mythread_pool() {} ~mythread_pool() { printf("thread pool destroy now, tid: %lu\r\n", acl::thread::thread_self()); } protected: // 基類虛函數,當子線程被建立時該虛函數將被調用 virtual bool thread_on_init() { const char* myname = "thread_on_init"; printf("%s: curr tid: %lu\r\n", myname, acl::thread::thread_self()); return true; } // 基類虛函數,當子線程退出前該虛函數將被調用 virtual void thread_on_exit() { const char* myname = "thread_on_exit"; printf("%s: curr tid: %lu\r\n", myname, acl::thread::thread_self()); } }; ////////////////////////////////////////////////////////////////////////// void test() { acl::thread_pool* threads = new mythread_pool(); threads->start(); // 啓動線程池過程 acl::thread_job *job1= new mythread, *job2 = new mythread; threads->execute(job1); threads->execute(job2); // 爲了保證 job1, job2動態內存被正確釋放, // 必須調用 threads->stop 等待子線程運行結束後在 // 主線程中將其釋放 threads->stop(); delete threads; // 在主線程中釋放動態分配的對象 delete job1; delete job2; }
如上例所示,在使用 acl 的C++版本線程池類庫時,必須定義一個線程工做類(繼承自 acl::thread_job)並實現基類的純虛函數:run();另外,在使用線程池時,若是想要在線程建立時初始化一些線程局部變量以及在線程退出 前釋放一些線程局部變量,則能夠定義 acl::thread_pool 的子類,實現基類中的 thread_on_init 和 thread_on_exit 方法,若是不須要,則能夠直接使用 acl::thread_pool 類對象。併發
下載:http://sourceforge.net/projects/acl/svn
svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code函數
github:https://github.com/zhengshuxin/acl高併發
QQ 羣:242722074 .net