跨平台多线程编程
??? official site:?http://sourceware.org/pthreads-win32/.?
??? source code:?ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-8-0-release.tar.gz
1. 編譯:?
??? 雖然源碼包里提供了vc6的項目文件, 但是打不開的, 只能用nmake. 默認的會告訴你一堆nmake參數的.?
??? 我所要用的是編譯成static的library, 所以輸入"nmake clean VC-static", 編譯很快的. 不過默認會鏈接到VC的crt, 我們需要修改它的makefile. 找到CFLAGS那一行, 把"/MD"改成"/MT".?
2. 項目:?
??? 誒.. 有好多地方要改的.?
??? a) 當然是vs路徑的include啊, lib啊.. 自己加.?
??? b) 項目的crt設置成"/MT"和"/MTd". 額外的lib加: pthreadVC2(d).lib ws2_32.lib
??? c) preprocesser定義的地方, 加一個“PTW32_STATIC_LIB”宏, 不然link的時候會找不到symbol的.?
??? d) 好了, 你可以coding了, 隨便pthread_create()一把吧.?
3. 編碼:?
??? 嗯嗯.. 如果真的直接pthread_create()的話可是會access violation的呀. win32下的線程很詭異的, 像winsock一樣, 調用任何其它函數之前必須調用pthread_win32_process_attach_np(), 結束后必須調用pthread_win32_process_detach_np(). 代碼大概就是這樣的:?
int?main()
{
#ifdef?WIN32
#ifdef?PTW32_STATIC_LIB
????pthread_win32_process_attach_np();
#endif
#endif
????/* do something with pthread library */
#ifdef?WIN32
#ifdef?PTW32_STATIC_LIB
????pthread_win32_process_detach_np();
#endif
#endif
}
#include?<stdio.h>
#include?<stdlib.h>
#include?<pthread.h>
?
pthread_mutex_t????count_mutex??? ??? =?PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t????condition_mutex?=?PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t????condition_cond? =?PTHREAD_COND_INITIALIZER;
?
void?*functionCount1(void*?param);
void?*functionCount2(void*?param);
int?count?= 0;
#define?COUNT_DONE??? 10
#define?COUNT_HALT1??? 3
#define?COUNT_HALT2??? 6
?
int?main()
{
#ifdef?WIN32
#ifdef?PTW32_STATIC_LIB
????pthread_win32_process_attach_np();
#endif
#endif
?
????pthread_t?thread1,?thread2;
????pthread_create(&thread1, 0,?functionCount1, 0);
????pthread_create(&thread2, 0,?functionCount2, 0);
????pthread_join(thread1, 0);
????pthread_join(thread2, 0);
?
#ifdef?WIN32
#ifdef?PTW32_STATIC_LIB
????pthread_win32_process_detach_np();
#endif
#endif
????return?0;
}
?
void?*functionCount1(void*?param)
{
????for?(;;)
??? {
??? ????pthread_mutex_lock(&condition_mutex);
??? ????while?(count?>=?COUNT_HALT1?&&?count?<=?COUNT_HALT2)
??? ??? {
??? ??? ????pthread_cond_wait(&condition_cond, &condition_mutex);
??? ??? ????/* ... */
??? ??? }
??? ????pthread_mutex_unlock(&condition_mutex);
?
??? ????pthread_mutex_lock(&count_mutex);
??? ????count++;
??? ????printf("Counter value functionCount1: %d\n",?count);
??? ????pthread_mutex_unlock(&count_mutex);
?
??? ????if?(count?>=?COUNT_DONE)?return?0;
??? }
}
?
void?*functionCount2(void*?param)
{
????for?(;;)
??? {
??? ????pthread_mutex_lock(&condition_mutex);
??? ????if?(count?<?COUNT_HALT1?||?count?>?COUNT_HALT2)
??? ??? {
??? ??? ????pthread_cond_signal(&condition_cond);
??? ??? }
??? ????pthread_mutex_unlock(&condition_mutex);
?
??? ????pthread_mutex_lock(&count_mutex);
??? ????count++;
??? ????printf("Counter value functionCount2: %d\n",?count);
??? ????pthread_mutex_unlock(&count_mutex);
?
??? ????if?(count?>=?COUNT_DONE)?return?0;
??? }
}
??? 舉這個例子只是為了說明pthread_cond_signal()和pthread_cond_wait()的用法. 注意到區別了么, 一個用if來判斷, 一個用的則是while. 之所以要這樣是由于pthread_cond_wait()這個函數很特別, 在進入這個函數開始會先解鎖(即解mutex), 離開這個函數時再次加鎖, 中間會有空隙, 必須要再次判斷. 所以如果注釋的地方有代碼的話, 是不能保證正確性的. 具體可以man一下自己看.?4. 參考:?
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
http://bbs.chinaunix.net/thread-1060780-1-1.html ? ======================================================================== ? 第一個多線程程序: ? 我們以最常見的helloworld 程序開始多線程之旅吧。代碼如下所示:?main.c?。 #include<pthread.h> void* thread_one(void* dummy) { ????? while(1) ????? { ?????????? printf("Hello,world.this is thread one\n"); ????? } ????? } ? void* thread_two(void* dummy) { ????? while(1) ????? { ?????????? printf("Hello,world.this is thread two\n"); ????? } ????? } ? int main(void) { ????? pthread_t tid[2]; ????? pthread_create(&tid[0],NULL,thread_one,NULL); ????? pthread_create(&tid[1],NULL,thread_two,NULL); ????? pthread_exit(NULL); } ? 編譯、鏈接: WIN32 VC中新建一個空的工程,加入上述代碼,在鏈接時記得加入pthreadVC2.lib。(在vc 中在“工程”->“設置”->“鏈接”中) ? LINUX: Gcc –o hello main.c –lpthread ? 運行程序就可以看到兩個線程在交互運行,不斷地出現各自打印的信息。 ? 從上面的程序看出,有了pthreads,開發跨平臺的多線程程序并不是難事。當然這里只是開始,后續的文章就詳細介紹?pthreads?的多線程開發。 ? ======================================================================================== (二) Pthreads 的API
在 pthreads 函數接口可以分為以下三類(關于函數的具體接口參考文章末尾):
1. 線程管理(thread management):用于線程創建、detach、join已經設置和查詢線程屬性的函數:主要函數有pthread_create,pthread_exit,pthread_detach,pthread_join。pthread_self
2. Mutex 操作函數:用來保證資源的互斥訪問,它用來實現多線程訪問數據時的同步機制。
主要函數有:pthread_mutex_init,pthread_mutex_lock,pthread_mutex_unlock
3.狀態變量操作函數: 這類函數用來建立共享mutex 的多線程通信。它根據程序員設定的條件來決定是否發出信號(signal)或者等待(wait)。主要函數有:pthread_cond_init,pthread_cond_signal: pthread_cond_wait。
?
在pthreads 常用的類型pthread_t 用來記錄每個線程的id。
?
下面開始對跨平臺多線程編程教程(一)中的例子進行說明。
?
第一行:#include <pthread.h> 包含了pthreads 中類型定義和函數接口。
pthread_t tid[2];? 用來存儲兩個線程的id
pthread_create(&tid[0],NULL,thread_one,NULL); 創建了第一個線程。這個線程開始執行thread_one 函數。
pthread_create(&tid[1],NULL,thread_two,NULL); 創建了第二個線程。這個線程開始執行thread_two 函數。
?
兩個線程都沒有傳遞參數(第四個參數為NULL)。開始執行后,線程間不斷地調度,交替地打印各自的字符串。
?
注意:在前面的例子的main函數的最后部分有調用了函數pthread_exit; 嘗試去掉這個語句再運行程序,你會發現兩個線程在打印了一些字符串后就退出了。原因是正常情況下,創建了兩個線程后,主線程調用 return 0 退出,它所創建的子線程也跟著退出。調用pthread_exit 后子線程就可以一直運行了。
?
后面的章節將對三類 pthreads API 進行相信的介紹。
?
pthreads 常用API 參考(源于網絡)
?
pthread_create(
?????????????? pthread_t *tid,
?????????????? const pthread_attr_t *attr,
?????????????? void*(*start_routine)(void*),
?????????????? void *arg
?????????????? );
用途:創建一個線程
//參數:tid 用于返回新創建線程的線程號;
//start_routine 是線程函數指針,線程從這個函數開始獨立地運行;
//arg 是傳遞給線程函數的參數。由于start_routine 是一個指向參數類型為void*,返回值為void*的指針,所以如果需要傳遞或返回多個參數時,可以使用強制類型轉化。
?
void pthread_exit(
??????????? void* value_ptr
???????????? );
用途:退出線程
參數:value_ptr 是一個指向返回狀態值的指針。
?
int pthread_join(
???????????? pthread_t tid ,
???????????? void **status
???????????? );
// 參數tid 是希望等待的線程的線程號,status 是指向線程返回值的指針,線程的返回值就是pthread_exit 中的value_ptr 參數,或者是return語句中的返回值。該函數可用于線程間的同步。
int pthread_mutex_init(
?????????????????? pthread_mutex_t *mutex,
?????????????????? const pthread_mutex_attr_t* attr
?????????????????? );
//該函數初始化一個互斥體變量,如果參數attr 為NULL,則互斥
//體變量mutex 使用默認的屬性。
int pthread_mutex_lock(
?????????????????? pthread_mutex_t *mutex
?????????????????? );
// 該函數用來鎖住互斥體變量。如果參數mutex 所指的互斥體已經
//被鎖住了,那么發出調用的線程將被阻塞直到其他線程對mutex 解鎖。
int pthread_mutex_trylock(
????????????????????? pthread_t *mutex
????????????????????? );
//該函數用來鎖住mutex 所指定的互斥體,但不阻塞。如果該互斥
//體已經被上鎖,該調用不會阻塞等待,而會返回一個錯誤代碼。
int pthread_mutex_unlock(
???????????????????? pthread_mutex_t *mutex
???????????????????? );
//該函數用來對一個互斥體解鎖。如果當前線程擁有參數mutex 所
//指定的互斥體,該調用將該互斥體解鎖。
int pthread_mutex_destroy (
?????????????????????? pthread_mutex_t *mutex
?????????????????????? );
//該函數用來釋放分配給參數mutex 的資源。調用成功時返回值為
//0, 否則返回一個非0 的錯誤代碼。
int pthread_cond_init(
????????????????? pthread_cond_t *cond,
????????????????? const pthread_cond_attr_t*attr
????????????????? );
//該函數按參數attr指定的屬性創建一個條件變量。調用成功返回,
//并將條件變量ID 賦值給參數cond,否則返回錯誤代碼。
int pthread_cond_wait (
?????????????????? pthread_cond_t *cond ,
?????????????????? pthread_mutex_t*mutex
?????????????????? );
// 該函數調用為參數mutex 指定的互斥體解鎖,等待一個事件(由
//參數cond 指定的條件變量)發生。調用該函數的線程被阻塞直到有其他
//線程調用pthread_cond_signal 或pthread_cond_broadcast 函數置相應的條
//件變量,而且獲得mutex 互斥體時才解除阻塞。
int pthread_cond_timewait(
????????????????????? pthread_cond_t *cond ,
????????????????????? pthread_mutex_t*mutex ,
????????????????????? const struct timespec *abstime
????????????????????? );
// 該函數與pthread_cond_wait 不同的是當系統時間到達abstime 參數指定的時間時,被阻塞線程也可以被喚起繼續執行。
int pthread_cond_broadcast(
?????????????????????? pthread_cond_t *cond
?????????????????????? );
// 該函數用來對所有等待參數cond所指定的條件變量的線程解除阻塞,調用成功返回0,否則返回錯誤代碼。
int pthread_cond_signal(
??????????????????? pthread_cond_t *cond
??????????????????? );
// 該函數的作用是解除一個等待參數cond所指定的條件變量的線程的阻塞狀態。當有多個線程掛起等待該條件變量,也只喚醒一個線程。
int pthread_cond_destroy(
???????????????????? pthread_cond_t *cond
???????????????????? ); // 該函數的作用是釋放一個條件變量。釋放為條件變量cond 所分配的資源。調用成功返回值為0,否則返回錯誤代碼。
int pthread_key_create(
?????????????????? pthread_key_t key ,
?????????????????? void(*destructor(void*))
?????????????????? ); // 該函數創建一個鍵值,該鍵值映射到一個專有數據結構體上。如果第二個參數不是NULL,這個鍵值被刪除時將調用這個函數指針來釋放數據空間。
int pthread_key_delete(
?????????????????? pthread_key_t *key
?????????????????? );
// 該函數用于刪除一個由pthread_key_create 函數調用創建的TSD鍵。調用成功返回值為0,否則返回錯誤代碼。
int pthread_setspecific(
??????????????????? pthread_key_t key ,
??????????????????? const void(value)
??????????????????? );
// 該函數設置一個線程專有數據的值,賦給由pthread_key_create 創建的TSD 鍵,調用成功返回值為0,否則返回錯誤代碼。
void *pthread_getspecific(
??????????????????? pthread_key_t *key
??????????????????? ); // 該函數獲得綁定到指定TSD 鍵上的值。調用成功,返回給定參數key 所對應的數據。如果沒有數據連接到該TSD 鍵,則返回NULL。
int pthread_once(
???????????? pthread_once_t* once_control,
???????????? void(*init_routine)(void)
???????????? );
//該函數的作用是確保init_routine 指向的函數,在調用pthread_once的線程中只被運行一次。once_control 指向一個靜態或全局的變量。 ? ======================================================================================== ? 1. 下載pthreads win32源代碼:
????ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-8-0-release.tar.gz 2. 編譯靜態庫:
make clean GC-static
在根目錄下面生成libpthreadGC2.a 3. 將生成的libpthreadGC2.a拷貝到mingw庫目錄下,將pthread.h, sched.h, semaphore.h拷貝到INCLUDE目錄下 4. 使用libpthread庫, 在程序起始處對libpthread作初始化:
#if defined(PTW32_STATIC_LIB)
??? ptw32_processInitialize();
#endif 5. 編譯時確保傳入-DPTW32_STATIC_LIB,鏈接時加入-lpthreadGC2, OK!
總結
- 上一篇: IOS15自定义UICollection
- 下一篇: 李国杰院士:国内开源社区的崛起需要一个过