GB | BIG5
|
| 首頁 > 編程技術 > C/C++ > 正文 |
 |
| Solaris2.4 多線程編程指南2--用多線程編程 |
| 本文出自:BBS水木清華站 作者:Mccartney (coolcat) (2002-01-29 20:26:32) |
2 用多線程編程 2.1線程(函數)庫(The Threads Library) 用戶級多線程是通過線程庫,libthread來實現的(參考手冊第3頁: library routines)。線程庫支持信號,為可運行的程序排隊,並負責同 時操縱多任務。 這一章討論libthread中的一些通用過程,首先接觸基本操作,然循 序漸進地進入更復雜的內容。 創建線程-基本特性 Thr_create(3T) 獲得線程號 Thr_self(3T) 執行線程 Thr_yield(3T,the below is same) 掛起或繼續線程 Thr_suspend Thr_continue 向線程送信號 Thr_kill 設置線程的調用掩模 Thr_sigsetmask 終止線程 Thr-exit 等待線程終止 Thr-join 維護線程的私有數據 Thr_keycreate Thr_setspecific Thr_getspecific 創建線程-高級特性 Thr_create 獲得最小堆棧容量 Thr_min_stack 獲得或設置線程的同時性等級 Thr_getconcurrency Thr_setconcurrency 獲得或設置線程的優先級 Thr_getprio Thr_setprio 2.1.1創建線程-基本篇 thr_create過程是線程庫所有過程當中最復雜的一個。這部分的內容僅適用你使用thr_create的缺省參數來創建進程。 對thr_create更加復雜的使用,包括如何使用自定參數,我們將在高級特性部分給出說明。 thr_create(3T) 這個函數用在當前進程中添加一個線程。注意,新的線程不繼承未處理的信號,但繼承優先級和信號掩模。 #include int thr_create(void *stack_base,size_t stack_size, void *(*start_routine) (void*),void *arg,long flags, thread_t *new_thread); size_t thr_min_stack(void); stack_base--新線程的堆棧地址。如果stack_base是空則thr_create()按 照stack_size為新線程分配一個堆棧。 Stack_size--新線程堆棧的字節數。如果本項為0,將使用缺省值,一般 情況下最好將此項設為0。並不是每個線程都需要指定堆棧空間。線程庫為每個線程的堆棧分配1M 的虛擬內存,不保留交換空間。(線程庫用mmap(2)的MAP_NORESERVE的選項 來實現這種分配)。 Start_routine--指定線程開始執行的函數。如果start_routine返回, 線程將用該函數的返回值作為退出狀態而退出。(參考thr_exit(3T))。 Flags--指定新線程的屬性,一般設置為0。 Flags的值是通過下列內容的位同或來實現的(最四個flags在高級特性中給出)。 1. THR_DETACHED 將新線程分離,使得它的線程號和其他資源在線程 結束時即可以回收利用。當你不想等待線程終止時,將其置位。如果沒有明確的 同步需求阻礙,一個不掛起的,分離的線程可以在創建者的thr_create返回之前 終止並將其線程號分配給一個心得線程。 2. THR_SUSPENDED掛起新線程,直到被thr_continue喚醒。 3. THR_BOUND把新線程永久綁定在一個LWP上(生成一個綁定線程)。 4. THR_NEW_LWP將非綁定線程的同時性級別加1。 5. THR_DAEMON新線程為一個守護線程。 New_thread--指向存儲新線程ID的地址。多數情況下設置為0。 Return Values--thr_create()在成功執行返回0並退出。任何其他返回值表明有錯誤發生。當以下情況被檢測到時,thr_create()失敗並返回響應的值。 EAGAIN :超出了系統限制,例如創建了太多的LWP。 ENOMEM:可用內存不夠創建新線程。 EINVAL:stack_base不是NULL而且stack_size比thr_minstack()函數返回的最小堆棧要小。 2.1.2獲取線程號 thr_self(3T) 獲得自身的線程號。 #include thread_t thr_self(void) 返回值--調用者的線程號。 2.1.3放棄執行 thr_yield(3T) thr_yield停止執行當前線程,將執行權限讓給有相同或更高優先權的線程。 #include void thr_yield(void); 2.1.4掛起或繼續執行線程 thr_suspend(3T) 掛起線程。 #include int thr_suspend(thread_t target_thread); thr_suspend()立即掛起由target_thread指定的線程。在thr_suspend成功返回,掛起的線程不再執行。繼的thr_suspend無效。 Return Values--執行成功返回0。其他返回值意味著錯誤。以下情況發生時,thr_suspend()失敗並返回相關值。 ESRCH: 在當前進程中找不到target_thread。 Thr_continue(3T) Thr_continue()恢復執行一個掛起的線程。一旦線程脫離掛起狀態,繼的 thr_continue將無效。 #include int thr_continue(thread_t target_thread); 一個掛起的線程不會被信號喚醒。信號被掛起知道線程被thr-continue恢復執行。 返回值--成功執行返回0。其他值意味著錯誤。在以下情況發生時,函數失敗並返回相關值。 ESRCH:target_thread在當前進程中找不到。 2.1.5向線程發信號 thr_kill(3T)向線程發信號 #include #include int thr_kill(thread_t target_thread,int sig); thr_kill向線程號為target_thread的線程發送信號sig。Target_thread一定要與調用線程處同一個進程內。參數sig一定是signal(5)中定義過的。 當sig是0時,錯誤檢查將被執行,沒有實際的信號被發送。這可以用來檢測arget_thread參數是否合法。 返回值--成功執行返回0,其他值意味著錯誤。在以下情況發生時,函數失敗並返回相關值。 EINVAL:sig非法; ESRCH:target_thread找不到; 2.1.6設置本線程的信號掩模 thr_sigsetmask(3T) 獲取或改變本線程的信號掩模(signal mask) #include #include int thr_sigsetmask(int how,const sigset_t *set,sigset_t *oset); how參數決定信號設置將被如何改變,可以是下列值之一: SIG_BLOCK--在當前信號掩模上增加set,set指要阻塞的信號組。 SIG_UNBLOCK--在當前信號掩模上去掉set,set指要解除阻塞的信號組。 SIG_SETMASK--用新的掩模代替現有掩模,set指新的信號掩模。 當set的值是NULL時,how的值並不重要,信號掩模將不被改變。所以,要查詢當前的信號掩模,就給set賦值為NULL。 當參數oset不是NULL時,它指向以前的信號掩模存放的地方。 Return Values--正常執行返回0。其他值意味著錯誤。在以下情況發生時, 函數失敗並返回相關值。 EINVAL:set不是NULL且how沒有被定義; EFAULT:set或oset不是合法地址; 2.1.7終止線程 thr_exit(3T) 用來終止一個線程。 #include void thr_exit(void *status); thr_exit 函數終止當前線程。所有的私有數據被釋放。如果調用線程不是一個分離線程,線程的ID和返回狀態保留直到有另外的線程在等待。否則返回狀態被忽略,線程號被立刻重新使用。 返回值--當調用線程是進程中的最一個非守護線程,進程將用狀態0退出。 當最初的線程從main()函數中返回時進程用該線程main函數的返回值退出。 線程可以通過兩種方式停止執行。第一種是從最初的過程中返回。第二種是 提供一個退出代碼,通過調用thr_exit()結束。下面的事情依賴在線程創建時 flags的設置。 線程A終止的缺省操作(當flags的相應位設為0時,執行缺省操作)是保持 狀態,直到其它線程(不妨設為B)通過"聯合"的方式得知線程A已經死亡。聯合 的結果是B線程得到線程A的退出碼,A自動消亡。你可以通過位或來給flags的 THR_DETACHED參數置位,使得線程在thr_exit()之或從最初過程返回立即消 亡。在這種情況下,它的退出碼不會被任何線程獲得。 有一個重要的特殊情況,在主線程--即最初存在的線程--從主函數返回或調 用了exit(),整個進程將終止。所以在主線程中要注意不要過早地從主函數main 返回。 如果主線程僅僅調用了thr_exit(),僅僅是它自己死亡,進程不會結束,進 程內的其他線程將繼續運行(當然,如果所有的線程都結束,進程也就結束了)。 如果一個線程是非分離的,在它結束一定要有其它進程與它"聯合",否則 該線程的資源就不會被回收而被新線程使用。所以如果你不希望一個線程被 "聯合",最好按照分離線程來創建。 另外一個flag參數是THR_DAEMON。使用這個標志創建的線程是守護線程,在 其他線程終止之,這些線程自動終止。這些守護線程在線程庫內部特別有用。 守護線程可以用庫內函數創建--在程序的其他部分是不可見的。當程序中所 有的其他線程終止,這些線程自動終止。如果它們不是守護線程,在其它線程終 止他們不會自動終止,進程不會自動結束。 2.1.8等待線程結束 thr_join(3T) 用thr_join函數來等待線程終止。 #include int thr_join(thread_t wait_for,thread_t *departed,void **status); thr_join()函數阻塞自身所在的線程,直到由wait_for指定的線程終止。指 定的線程一定與本線程在同一個進程內部,而且一定不是分離線程。當wait_for 參數為0時,thr_join等待任何一個非分離線程結束。換句話說,當不指定線程 號時,任何非分離線程的退出將導致thr_join()返回。 當departed參數不是NULL時,在thr_join正常返回時它指向存放終止線程ID 的地址。當status參數不是NULL時,在thr_join正常返回時它指向存放終止線程 退出碼的地址。 如果線程創建時指定了堆棧,在thr_join返回時堆棧可以被回收。由它返回 的線程號可以被重新分配。 不能有兩個線程同時等待同一個線程,如果出現這種情況,其中一個線程正 常返回,另外一個返回ESRCH錯誤。 返回值--thr_join()在正常執行返回0,其他值意味著錯誤。在以下情況 發生時,函數失敗並返回相關值。 ESRCH wait_for不合法,等待的線程為分離現成。 EDEADLK 等待自身結束。 最步驟 thr_join()有三個參數,提供了一定的靈活性。當你需要一個線程等待 直到另外一個指定的線程結束,應當把者的ID提供為第一參數。如果 需要等待到任何其他的線程結束,將第一參數置零。 如果調用者想知道是那個線程終止,第二參數應當是儲存死線程的ID的地址。 如果不感興趣,將該參數置零。最如果需要知道死線程的退出碼,應當指出接 收該錯誤碼的地址。 一個線程可以通過以下的代碼等待所有的非守護線程結束: while(thr_join(0,0,0)==0) 第三個參數的聲明(void **)看上去很奇怪。相應的thr_exit()的參數為 void *。這樣做的意圖在你的錯誤代碼為定長的四字節,c語言給定長4字節的 定義不能是void型,因為這以為著沒有參數。所以用void*。因為thr_join()的 第三參數必須是一個指向thr_exit()返回值的指針,所以類型必須是void **。 注意,thr_join()只在目標線程為非分離時有效。如果沒有特殊的同步要求 的話,線程一般都設置成分離的。 可以認為,分離線程是通常意義下的線程,而非分離線程知識特殊情況。 2.1.9簡單的例程 在例子2-1裡,一個運行在頂部的線程,創建一個輔助線程來執行fetch過程, 這個輔助過程涉及到復雜的數據庫查詢,需要較長的時間。主線程在等待結果的 時候還有其他事情可做。所以它通過執行thr_join()來等待輔助過程結束。 操作結果被當作堆棧參數傳送,因為主線程等待spun-off線程結束。在一般 意義上,用malloc()存儲數據比通過線程的堆棧來存儲要好一些。???? Code Example 2-1 A Simple Threads Program Void mainline(){ Char int result; Thread_t helper; Int status; Thr_create(0,0,fetch,&result,0,&helper); /* do something else for a while */ Thr_join(helper,0,&status); /* it's now safe to use result*/ } void fetch(int * result){ /*fetch value from a database */ *result=value; thr_exit(0); } 2.1.10維護線程專有數據 單線程C程序有兩種基本數據--本地數據和全局數據。多線程C程序增加了 一個特殊類型--線程專有數據(TSD)。非常類似與全局數據,只不過它是線程 私有的。 TSD是以線程為界限的。TSD是定義線程私有數據的唯一方法。每個線程專有 數據項都由一個進程內唯一的關鍵字(KEY)來標識。用這個關鍵字,線程可以 來存取線程私有的數據。 維護TSD的方法通過以下三個函數進行: ﹒ thr_keycreate()--創建關鍵字 ﹒ thr_setspecific()--將一個線程綁定在一個關鍵字上 ﹒ thr_getspecific()--存儲指定地址的值 2.1.10.1 thr_keycreate(3T) thr_keycreate()在進程內部分配一個標識TSD的關鍵字。關鍵字是進程內部唯一的,所有線程在創建時的關鍵字值是NULL。 一旦關鍵字被建立,每一個線程可以為關鍵字綁定一個值。這個值對綁定的線程來說是唯一的,被每個線程獨立維護。 #include int thr_keycreate(thread_key_t keyp, void (*destructor)(void *value); 如果thr_keycreate()成功返回,分配的關鍵字被存儲在由keyp指向的區 域裡。調用者一定要保証存儲和對關鍵字的訪問被正確地同步。 一個可選的析構函數,destructor,可以和每個關鍵字聯系起來。如果一 個關鍵字的destructor不空而且線程給該關鍵字一個非空值,在線程退出時該 析構函數被調用,使用當前的綁定值。對所有關鍵字的析構函數執行的順序 是不能指定的。 返回值--thr_keycreate()在正常執行返回0,其他值意味著錯誤。在以 下情況發生時,函數失敗並返回相關值。 EAGAIN 關鍵字的名字空間用盡 ENOMEM 內存不夠 2.1.10.2 Thr_setspecific(3T) #include int thr_setspecific(thread_key_t key,void *value); thr_setspecific()為由key指定的TSD關鍵字綁定一個與本線程相關的值。 返回值--thr_setspecific在正常執行返回0,其他值意味著錯誤。在以 下情況發生時,函數失敗並返回相關值。 ENOMEM 內存不夠 EINVAL 關鍵字非法 2.1.10.3 Thr_getspecific(3T) #include int thr_getspecific(thread_key_t key,void **valuep); thr_getspecific()將與調用線程相關的關鍵字的值存入由valuep指定的區 域。 返回值--thr_getspecific()在正常執行返回0,其他值意味著錯誤。在 以下情況發生時,函數失敗並返回相關值。 EINVAL 關鍵字非法。 2.1.10.5 全局和私有的線程專有數據 例程2-2是從一個多線程程序中摘錄出來的。這段代碼可以被任意數量的線 程執行,但一定要參考兩個全局變量:errno和mywindow,這兩個值是因線程而 異的,就是說是線程私有的。 Code Example 2-2 線程專有數據--全局且私有的 Body(){ …… while(srite(fd,buffer,size)==-1){ if(errno!=EINTR){ fprintf(mywindow,"%s\n",strerror(errno)); exit(1); } } ……… } 本線程的系統錯誤代碼errno可以通過線程的系統調用來獲得,而不是通過 其他線程。所以一個線程獲得的錯誤碼與其他線程是不同的。 變量mywindow指向一個線程私有的輸入輸出流。所以,一個線程的mywindow 和另外一個線程是不同的,因而最終體現在不同的窗口裡。唯一的區別在線程 庫來處理errno,而程序員需要精心設計mywindow。 下面一個例子說明了mywindow的設計方法。處理器把mywindow的指針轉換成為對_mywindow過程的調用。 然調用thr_getspecific(),把全程變量mywindow_key和標識線程窗口的輸出參數win傳遞給它。 Code Example 2-3 將全局參考轉化為私有參考 #define mywindow _mywindow() thread_key_t mywindow_key; FILE * _mywindow(void){ FILE *win; Thr_getspecific(mywindow_key,&win); Return(win); } void thread_start(…){ … make_mywindow(); … } 變量mywindow標識了一類每個線程都有私有副本的變量;就是說,這些變量 是線程專有數據。每個線程調用make_mywindow()來初始化自己的窗口,並且生 成一個指向它的實例mywindow。 一旦過程被調用,現成可以安全地訪問mywindow,在_mywindow函數之,線 程可以訪問它的私有窗口。所以,對mywindow的操作就象是直接操作線程私有 數據一樣。 Code Example 2-4 顯示了怎樣設置 Code Example 2-4 初始化TSD Void make_mywindow(void){ FILE **win; Static int once=0; Static mutex_t lock; Mutex_lock(&lock); If (!once){ Once=1; Thr_keycreate(&mywindow_key,free_key); } mutext_unlock(&lock); win=malloc(sizeof(*win)); create_window(win,…); thr_setspecific(mywindow_key,win); } void freekey(void *win){ free(win); } 首先,給關鍵字mywindow_key賦一個唯一的值。這個關鍵字被用標識 TSD。所以,第一個調用make_mywindow的線程調用thr_keycreate(),這個函 數給其第一個參數賦一個唯一的值。第二個參數是一個析構函數,用來在線程 終止將TSD所佔的空間回收。 下一步操作是給調用者分配一個TSD的實例空間。分配空間以,調用 create_window過程,為線程建立一個窗口並用win來標識它。最調用 thr_setspecific(),把win(即指向窗口的存儲區)的值與關鍵字綁在一起。 做完這一步,任何時候線程調用thr_getspecific(),傳送全局關鍵字, 它得到的都是該線程在調用thr_setspecific時與關鍵字綁定的值。 如果線程結束,在thr_keycreate()中建立的析構函數將被調用,每個析構 函數只有在終止的線程用thr_setspecific()為關鍵字賦值之才會執行。 2.1.11創建線程--高級特性 2.1.11.1 thr_create(3T) #include int thr_create(void *stack_base,size_t stack_size, void *(*start_routine)(void *),void * arg, long flags,thread_t *newthread); size_t thr_min_stack(void); stack_base--新線程所用的堆棧地址。如果本參數為空,thr_create為新線程分配一個至少長stack_size的堆棧。 Stack_size--新線程使用堆棧的字節數。如果本參數為零,將使用缺省值。如果非零,一定要比調用thr_min_stack()獲得的值大。 一個最小堆棧也許不能容納start_routine需要的堆棧大小,所以如果 stack_size被指定,一定要保証它是最小需求與start_routine及它所調用的 函數需要的堆棧空間之和。 典型情況下,由thr_create()分配的線程堆棧從一個頁邊界開始,到離指 定大小最接近的頁邊界結束。在堆棧的頂部放置一個沒有訪問權限的頁,這樣, 大多數堆棧溢出錯誤發生在向越界的線程發送SIGSEGV信號的時候。由調用者分 配的線程堆棧 are used as is . ???? 如果調用者使用一個預分配的堆棧,在指向該線程的thr_join()函數返回 之前,堆棧將不被釋放,即使線程已經終止。然線程用該函數的返回值作為 退出碼退出。 通常情況下,你不需要為線程分配堆棧空間。線程庫為每個線程的堆棧分 配一兆的虛擬內存,不保留交換空間(線程庫用mmap(2)的MAP_NORESERVE選項 來進行分配)。 每個用線程庫創建的線程堆棧有一個"紅區"。線程庫將一個紅區放置在堆 棧頂部來檢測溢出。該頁是沒有訪問權限的,在訪問時將導致一個頁錯誤。紅 區被自動附加在堆棧頂端,不管是用指定的容量還是缺省的容量。 只有在你絕對確信你給的參數正確之才可以指定堆棧。沒有多少情況需 要去指定堆棧或它的大小。即使是專家也很難知道指定的堆棧和容量是否正確。 這是因為遵循ABI的程序不能靜態地決定堆棧的大小。它的大小依賴運行時的 環境。 2.1.11.2建立你自己的堆棧 如果你指定了線程堆棧的大小,要保証你考慮到了調用它的函數和它調用的函數需要的空間。需要把調用結果、本地變量和消息結構的成分都考慮進來。 偶爾你需要一個與缺省堆棧略有不同的堆棧。一個典型的情況是當線程需 要一兆以上的堆棧空間。一個不太典型的情況是缺省堆棧對你來說太大了。 你可能會創建上千個線程,如果使用缺省堆棧時,就需要上G的空間。 堆棧的上限是很顯然的,但下限呢?一定要有足夠的堆棧空間來保存堆棧 框架和本地變量。 你可以用thr_min_stack()函數來獲得絕對的最小堆棧容量,它返回運行一 個空過程所需要的堆棧空間。有實際用途的線程需要的更多,所以在減小線程 堆棧的時候要小心。 你通過兩種方式指定一個堆棧。第一種是給堆棧地址賦空值,由實時的運 行庫來為堆棧分配空間,但需要給stack_size參數提供一個期望的值。 另外一種方式是全面了解堆棧管理,為thr_create函數提供一個堆棧的指 針。這意味著你不但要負責為堆棧分配空間,你還要考慮在線程結束釋放這 些空間。 在你為自己的堆棧分配空間之,一定要調用一個mprotect(2)函數來為它 附加一個紅區。 Start_routine--指定新線程首先要執行的過程。當start_routine返回時, 線程用該返回值作為退出碼退出(參考thr_exit(3T))。 注意,你只能指定一個參數。如果你想要多參數,把他們作成一個(例如 寫入一個結構)。這個參數可以是任何一個由void說明的數據,典型的是一個 4字節的值。任何更大的值都需要用指針來間接傳送。 Flags--指定創建線程的屬性。在多數情況下提供0即可。 Flags的值通過位或操作來賦。 THR_SUSPENDED--新線程掛起,在thr_continue()再執行 start_routine。用這種辦法在運行線程之前對它進行操作(例如改變 優先級)。分離線程的終止被忽略。 THR_DETACHED--將新線程分離,使線程一旦終止,其資源可以得到立刻 回收利用。如果你不需要等待線程結束,設置此標志。 如果沒有明確的同步要求,一個不掛起的,分離的線程可以在它 的創建者調用的thr_create函數返回之前終止並將線程號和其他資源 移交給其他線程使用。 THR_BOUND--將一個新線程永久綁定在一個LWP上(新線程為綁定線程)。 THR_NEW_LWP--給非綁定線程的同時性等級加1。效果類似用 thr_setconcurrency(3T)來增加同時性等級,但是使用 thr_setconcurrency()不影響等級設置。典型的,THR_NEW_LWP在LWP池 內增加一個LWP來運行非綁定線程。 如果你同時指定了THR_BOUND和THR_NEW_LWP,兩個LWP被創建,一 個被綁定在該線程上,另外一個來運行非綁定線程。 THR_DAEMON--標志新線程為守護線程。當所有的非守護線程退出進程 結束。守護線程不影響進程退出狀態,在統計退出的線程數時被忽略。 一個進程可以通過調用exit(2)或者在所有非守護線程調用 thr_exit(3T)函數終止的時候終止。一個應用程序,或它調用的一個庫, 可以創建一個或多個在決定是否退出的時候被忽略的線程。用 THR_DAEMON標志創建的線程在進程退出的范疇不被考慮。 New_thread--在thr_create()成功返回,保存指向存放新線程ID的地址。 調用者負責提供保存這個參數值指向的空間。 如果你對這個值不感興趣,給它賦值0。 返回值--thr_thread在正常執行返回0,其他值意味著錯誤。在以下情況 發生時,函數失敗並返回相關值。 EAGAIN 超過系統限制,例如創建了太多的LWP。 ENOMEM 內存不夠創建新線程。 EINVAL stack_base非空,但stack_size比thr_minstack()的返回值小。 2.1.11.3 Thr_create(3T)例程 例2-5顯示了怎樣用一個與創建者(orig_mask)不同的新的信號掩模來創建新線程。 在這個例子當中,new_mask被設置為屏蔽SIGINT以外的任何信號。然創建者的信號掩模被改變,以便新線程繼承一個不同的掩模,在thr_create()返回,創建者的掩模被恢復為原來的樣子。 例子假設SIGINT不被創建者屏蔽。如果最初是屏蔽的,用相應的操作去掉屏蔽。另外一種辦法是用新線程的start routine來設置它自己的信號掩模。 Code Example 2-5 thr_create() Creates Thread With New Signal Mask thread_t tid; sigset_t new_mask, orig_mask; int error; (void)sigfillset(&new_mask); (void)sigdelset(&new_mask, SIGINT); (void)thr_sigsetmask(SIGSETMASK, &new_mask, &orig_mask): error = thr_create(NULL, 0, dofunc, NULL, 0, &tid); (void)thr_sigsetmask(SIGSETMASK, NULL, &orig_mask); 2.1.12獲得最小堆棧 thr_min_stack(3T) 用thr_min_stack(3T)來獲得線程的堆棧下限 #include size_t thr_min_stack(void); thr_min_stack()返回執行一個空線程所需要的堆棧大小(空線程是一個創 建出來執行一個空過程的線程)。 如果一個線程執行的不僅僅是空過程,應當給它分配比thr_min_stack()返 回值更多的空間。 如果線程創建時由用戶指定了堆棧,用戶應當為該線程保留足夠的空間。在 一個動態連接的環境裡,確切知道線程所需要的最小堆棧是非常困難的。 大多數情況下,用戶不應當自己指定堆棧。用戶指定的堆棧僅僅用來支持那 些希望控制它們的執行環境的應用程序。 一般的,用戶應當讓線程庫來處理堆棧的分配。線程庫提供的缺省堆棧足夠 運行任何線程。 2.1.13設置線程的同時性等級 2.1.13.1 thr_getconcurrency(3T) 用thr_getconcurrency()來獲得期望的同時性等級的當前值。實際上同時活動的線程數可能會比這個數多或少。 #include int thr_getconcurrency(void) 返回值--thr_getconcurrency()為期望的同時性等級返回當前值。 2.1.13.2 Thr_setconcurrency(3T) 用thr_setconcurrency()設置期望的同時性等級。 #include int thr_setconcurrency(new_level) 進程中的非綁定線程可能需要同時活動。為了保留系統資源,線程系統的缺 省狀態保証有足夠的活動線程來運行一個進程,防止進程因為缺少同時性而死鎖。 因為這也許不會創建最有效的同時性等級,thr_setconcurrency()允許應用 程序用new_level給系統一些提示,來得到需要的同時性等級。 實際的同時活動的線程數可能比new_level多或少。 注意,如果沒有用thr_setconcurrency調整執行資源,有多個 compute-bound(????)線程的應用程序將不能分配所有的可運行線程。 你也可以通過在調用thr_create()時設置THR_NEW_LWP標志來獲得期望的同時性等級。 返回值--thr_setconcurrency()在正常執行返回0,其他值意味著錯誤。在以下情況發生時,函數失敗並返回相關值。 EAGAIN 指定的同時性等級超出了系統資源的上限。 EINVAL new_level的值為負。 2.1.14得到或設定線程的優先級 一個非綁定線程在調度時,系統僅僅考慮進程內的其他線程的簡單的優先級, 不做調整,也不涉及內核。線程的系統優先級的形式是唯一的,在創建進程時繼 承而來。 2.1.14.1 Thr_getprio(3T) 用thr_getprio()來得到線程當前的優先級。 #include int thr_getprio(thread_t target_thread,int *pri) 每個線程從它的創建者那裡繼承優先級,thr_getprio把target_thread當前 的優先級保存到由pri指向的地址內。 返回值--thr_getprio()在正常執行返回0,其他值意味著錯誤。在以下情 況發生時,函數失敗並返回相關值。 ESRCH target_thread在當前進程中不存在。 2.1.14.2 Thr_setprio(3T) 用thr_setprio()來改變線程的優先級。 #include int thr_setprio(thread_t target_thread,int pri) thr_setprio改變用target_thread指定的線程的優先級為pri。缺省狀態下, 線程的調度是按照固定的優先級--從0到最大的整數--來進行的,即使不全由優先 級決定,它也佔有非常重要的地位。Target_thread將打斷低優先級的線程,而讓 位給高優先級的線程。 返回值--thr_setprio()在正常執行返回0,其他值意味著錯誤。在以下情況發生時,函數失敗並返回相關值。 ESRCH target_thread在當前進程中找不到。 EINVAL pri的值對和target_thread相關的調度等級來說沒有意義。 2.1.15線程調度和線程庫函數 下面的libthread函數影響線程調度 2.1.15.1 thr_setprio()和thr_getprio() 這兩個函數用來改變和檢索target_thread的優先級,這個優先級在用戶級線程庫調度線程時被引用,但與操作系統調度LWP的優先級無關。 這個優先級影響線程和LWP的結合--如果可運行的線程比LWP多的時候,高優 先級的線程得到LWP。線程的調度是"專橫"的,就是說,如果有一個高優先級的線 程得不到空閑的LWP,而一個低優先級的線程佔有一個LWP,則低優先級的線程被 迫將LWP讓給高優先級的線程。 2.1.15.2 thr_suspend()和thr_continue() 這兩個函數控制線程是否被允許運行。調用thr_suspend(),可以把線程設置 為掛起狀態。就是說,該線程被擱置,即使有可用的LWP。在其他線程以該線程為 參數調用thr_continue,線程退出掛起狀態。這兩個函數應當小心使用--它們 的結果也許是危險的。例如,被掛起的線程也許是處在互鎖狀態的,將它掛起可 能會導致死鎖。 一個線程可以在創建時用THR_SUSPENDED標志設置為掛起。 2.1.15.3 thr_yield() Thr_yield函數使線程在相同優先級的線程退出掛起狀態交出LWP。(不會有 更高優先級的線程可運行而沒有運行,因為它會通過強制的方式取得LWP)。這個 函數具有非常重要的意義,因為在LWP上沒有分時的概念(盡管操作系統在執行LWP 時有分時)。 最,應當注意priocntl(2)也會影響線程調度。更詳細的內容請參照"LWP和調度等級"。
(http://www.fanqiang.com)
進入【UNIX論壇】
|
|
| 相關文章 |
Solaris2.4 多線程編程指南7--編程指南 (2002-01-29 20:33:46) Solaris2.4 多線程編程指南6--編譯和調試 (2002-01-29 20:32:52) Solaris2.4 多線程編程指南5--安全和不安全的接口函數 (2002-01-29 20:32:05) Solaris2.4 多線程編程指南4--操作系統編程 (2002-01-29 20:29:36) Solaris2.4 多線程編程指南3--使用同步對象編程 (2002-01-29 20:28:07) Solaris2.4 多線程編程指南2--用多線程編程 (2002-01-29 20:26:32) Solaris2.4 多線程編程指南1--線程基礎 (2002-01-29 20:25:25) Linux下的多線程編程 (2001-08-11 09:05:00)
|
|
|
|
 |
★ 樊強制作 歡迎分享 ★ |