跨平台多线程编程
??? 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. 默認(rèn)的會告訴你一堆nmake參數(shù)的.?
??? 我所要用的是編譯成static的library, 所以輸入"nmake clean VC-static", 編譯很快的. 不過默認(rèn)會鏈接到VC的crt, 我們需要修改它的makefile. 找到CFLAGS那一行, 把"/MD"改成"/MT".?
2. 項目:?
??? 誒.. 有好多地方要改的.?
??? a) 當(dāng)然是vs路徑的include啊, lib啊.. 自己加.?
??? b) 項目的crt設(shè)置成"/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一樣, 調(diào)用任何其它函數(shù)之前必須調(diào)用pthread_win32_process_attach_np(), 結(jié)束后必須調(diào)用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()的用法. 注意到區(qū)別了么, 一個用if來判斷, 一個用的則是while. 之所以要這樣是由于pthread_cond_wait()這個函數(shù)很特別, 在進(jìn)入這個函數(shù)開始會先解鎖(即解mutex), 離開這個函數(shù)時再次加鎖, 中間會有空隙, 必須要再次判斷. 所以如果注釋的地方有代碼的話, 是不能保證正確性的. 具體可以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 中在“工程”->“設(shè)置”->“鏈接”中) ? LINUX: Gcc –o hello main.c –lpthread ? 運行程序就可以看到兩個線程在交互運行,不斷地出現(xiàn)各自打印的信息。 ? 從上面的程序看出,有了pthreads,開發(fā)跨平臺的多線程程序并不是難事。當(dāng)然這里只是開始,后續(xù)的文章就詳細(xì)介紹?pthreads?的多線程開發(fā)。 ? ======================================================================================== (二) Pthreads 的API
在 pthreads 函數(shù)接口可以分為以下三類(關(guān)于函數(shù)的具體接口參考文章末尾):
1. 線程管理(thread management):用于線程創(chuàng)建、detach、join已經(jīng)設(shè)置和查詢線程屬性的函數(shù):主要函數(shù)有pthread_create,pthread_exit,pthread_detach,pthread_join。pthread_self
2. Mutex 操作函數(shù):用來保證資源的互斥訪問,它用來實現(xiàn)多線程訪問數(shù)據(jù)時的同步機制。
主要函數(shù)有:pthread_mutex_init,pthread_mutex_lock,pthread_mutex_unlock
3.狀態(tài)變量操作函數(shù): 這類函數(shù)用來建立共享mutex 的多線程通信。它根據(jù)程序員設(shè)定的條件來決定是否發(fā)出信號(signal)或者等待(wait)。主要函數(shù)有:pthread_cond_init,pthread_cond_signal: pthread_cond_wait。
?
在pthreads 常用的類型pthread_t 用來記錄每個線程的id。
?
下面開始對跨平臺多線程編程教程(一)中的例子進(jìn)行說明。
?
第一行:#include <pthread.h> 包含了pthreads 中類型定義和函數(shù)接口。
pthread_t tid[2];? 用來存儲兩個線程的id
pthread_create(&tid[0],NULL,thread_one,NULL); 創(chuàng)建了第一個線程。這個線程開始執(zhí)行thread_one 函數(shù)。
pthread_create(&tid[1],NULL,thread_two,NULL); 創(chuàng)建了第二個線程。這個線程開始執(zhí)行thread_two 函數(shù)。
?
兩個線程都沒有傳遞參數(shù)(第四個參數(shù)為NULL)。開始執(zhí)行后,線程間不斷地調(diào)度,交替地打印各自的字符串。
?
注意:在前面的例子的main函數(shù)的最后部分有調(diào)用了函數(shù)pthread_exit; 嘗試去掉這個語句再運行程序,你會發(fā)現(xiàn)兩個線程在打印了一些字符串后就退出了。原因是正常情況下,創(chuàng)建了兩個線程后,主線程調(diào)用 return 0 退出,它所創(chuàng)建的子線程也跟著退出。調(diào)用pthread_exit 后子線程就可以一直運行了。
?
后面的章節(jié)將對三類 pthreads API 進(jìn)行相信的介紹。
?
pthreads 常用API 參考(源于網(wǎng)絡(luò))
?
pthread_create(
?????????????? pthread_t *tid,
?????????????? const pthread_attr_t *attr,
?????????????? void*(*start_routine)(void*),
?????????????? void *arg
?????????????? );
用途:創(chuàng)建一個線程
//參數(shù):tid 用于返回新創(chuàng)建線程的線程號;
//start_routine 是線程函數(shù)指針,線程從這個函數(shù)開始獨立地運行;
//arg 是傳遞給線程函數(shù)的參數(shù)。由于start_routine 是一個指向參數(shù)類型為void*,返回值為void*的指針,所以如果需要傳遞或返回多個參數(shù)時,可以使用強制類型轉(zhuǎn)化。
?
void pthread_exit(
??????????? void* value_ptr
???????????? );
用途:退出線程
參數(shù):value_ptr 是一個指向返回狀態(tài)值的指針。
?
int pthread_join(
???????????? pthread_t tid ,
???????????? void **status
???????????? );
// 參數(shù)tid 是希望等待的線程的線程號,status 是指向線程返回值的指針,線程的返回值就是pthread_exit 中的value_ptr 參數(shù),或者是return語句中的返回值。該函數(shù)可用于線程間的同步。
int pthread_mutex_init(
?????????????????? pthread_mutex_t *mutex,
?????????????????? const pthread_mutex_attr_t* attr
?????????????????? );
//該函數(shù)初始化一個互斥體變量,如果參數(shù)attr 為NULL,則互斥
//體變量mutex 使用默認(rèn)的屬性。
int pthread_mutex_lock(
?????????????????? pthread_mutex_t *mutex
?????????????????? );
// 該函數(shù)用來鎖住互斥體變量。如果參數(shù)mutex 所指的互斥體已經(jīng)
//被鎖住了,那么發(fā)出調(diào)用的線程將被阻塞直到其他線程對mutex 解鎖。
int pthread_mutex_trylock(
????????????????????? pthread_t *mutex
????????????????????? );
//該函數(shù)用來鎖住mutex 所指定的互斥體,但不阻塞。如果該互斥
//體已經(jīng)被上鎖,該調(diào)用不會阻塞等待,而會返回一個錯誤代碼。
int pthread_mutex_unlock(
???????????????????? pthread_mutex_t *mutex
???????????????????? );
//該函數(shù)用來對一個互斥體解鎖。如果當(dāng)前線程擁有參數(shù)mutex 所
//指定的互斥體,該調(diào)用將該互斥體解鎖。
int pthread_mutex_destroy (
?????????????????????? pthread_mutex_t *mutex
?????????????????????? );
//該函數(shù)用來釋放分配給參數(shù)mutex 的資源。調(diào)用成功時返回值為
//0, 否則返回一個非0 的錯誤代碼。
int pthread_cond_init(
????????????????? pthread_cond_t *cond,
????????????????? const pthread_cond_attr_t*attr
????????????????? );
//該函數(shù)按參數(shù)attr指定的屬性創(chuàng)建一個條件變量。調(diào)用成功返回,
//并將條件變量ID 賦值給參數(shù)cond,否則返回錯誤代碼。
int pthread_cond_wait (
?????????????????? pthread_cond_t *cond ,
?????????????????? pthread_mutex_t*mutex
?????????????????? );
// 該函數(shù)調(diào)用為參數(shù)mutex 指定的互斥體解鎖,等待一個事件(由
//參數(shù)cond 指定的條件變量)發(fā)生。調(diào)用該函數(shù)的線程被阻塞直到有其他
//線程調(diào)用pthread_cond_signal 或pthread_cond_broadcast 函數(shù)置相應(yīng)的條
//件變量,而且獲得mutex 互斥體時才解除阻塞。
int pthread_cond_timewait(
????????????????????? pthread_cond_t *cond ,
????????????????????? pthread_mutex_t*mutex ,
????????????????????? const struct timespec *abstime
????????????????????? );
// 該函數(shù)與pthread_cond_wait 不同的是當(dāng)系統(tǒng)時間到達(dá)abstime 參數(shù)指定的時間時,被阻塞線程也可以被喚起繼續(xù)執(zhí)行。
int pthread_cond_broadcast(
?????????????????????? pthread_cond_t *cond
?????????????????????? );
// 該函數(shù)用來對所有等待參數(shù)cond所指定的條件變量的線程解除阻塞,調(diào)用成功返回0,否則返回錯誤代碼。
int pthread_cond_signal(
??????????????????? pthread_cond_t *cond
??????????????????? );
// 該函數(shù)的作用是解除一個等待參數(shù)cond所指定的條件變量的線程的阻塞狀態(tài)。當(dāng)有多個線程掛起等待該條件變量,也只喚醒一個線程。
int pthread_cond_destroy(
???????????????????? pthread_cond_t *cond
???????????????????? ); // 該函數(shù)的作用是釋放一個條件變量。釋放為條件變量cond 所分配的資源。調(diào)用成功返回值為0,否則返回錯誤代碼。
int pthread_key_create(
?????????????????? pthread_key_t key ,
?????????????????? void(*destructor(void*))
?????????????????? ); // 該函數(shù)創(chuàng)建一個鍵值,該鍵值映射到一個專有數(shù)據(jù)結(jié)構(gòu)體上。如果第二個參數(shù)不是NULL,這個鍵值被刪除時將調(diào)用這個函數(shù)指針來釋放數(shù)據(jù)空間。
int pthread_key_delete(
?????????????????? pthread_key_t *key
?????????????????? );
// 該函數(shù)用于刪除一個由pthread_key_create 函數(shù)調(diào)用創(chuàng)建的TSD鍵。調(diào)用成功返回值為0,否則返回錯誤代碼。
int pthread_setspecific(
??????????????????? pthread_key_t key ,
??????????????????? const void(value)
??????????????????? );
// 該函數(shù)設(shè)置一個線程專有數(shù)據(jù)的值,賦給由pthread_key_create 創(chuàng)建的TSD 鍵,調(diào)用成功返回值為0,否則返回錯誤代碼。
void *pthread_getspecific(
??????????????????? pthread_key_t *key
??????????????????? ); // 該函數(shù)獲得綁定到指定TSD 鍵上的值。調(diào)用成功,返回給定參數(shù)key 所對應(yīng)的數(shù)據(jù)。如果沒有數(shù)據(jù)連接到該TSD 鍵,則返回NULL。
int pthread_once(
???????????? pthread_once_t* once_control,
???????????? void(*init_routine)(void)
???????????? );
//該函數(shù)的作用是確保init_routine 指向的函數(shù),在調(diào)用pthread_once的線程中只被運行一次。once_control 指向一個靜態(tài)或全局的變量。 ? ======================================================================================== ? 1. 下載pthreads win32源代碼:
????ftp://sourceware.org/pub/pthreads-win32/pthreads-w32-2-8-0-release.tar.gz 2. 編譯靜態(tài)庫:
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!
總結(jié)
- 上一篇: IOS15自定义UICollection
- 下一篇: ios15 LJScrollPageVC