<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                **Linux下多線程詳解pdf文檔下載:[點擊這里!](http://download.csdn.net/detail/qq_21792169/9380962)** 線程與進程 為什么有了進程的概念后,還要再引入線程呢?使用多線程到底有哪些好處?什么的系統應該選用多線程?我們首先必須回答這些問題。 使用多線程的理由之一是和進程相比,它是一種非常"節儉"的多任務操作方式。我們知道,在Linux系統下,啟動一個新的進程必須分配給它獨立的地址空間,建立眾多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工作方式。而運行于一個進程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分數據,啟動一個線程所花費的空間遠遠小于啟動一個進程所花費的空間,而且,線程間彼此切換所需的時間也遠遠小于進程間切換所需要的時間。據統計,總的說來,一個進程的開銷大約是一個線程開銷的30倍左右,當然,在具體的系統上,這個數據可能會有較大的區別。 使用多線程的理由之二是線程間方便的通信機制。對不同進程來說,它們具有獨立的數據空間,要進行數據的傳遞只能通過通信的方式進行,這種方式不僅費時,而且很不方便。線程則不然,由于同一進程下的線程之間共享數據空間,所以一個線程的數據可以直接為其它線程所用,這不僅快捷,而且方便。當然,數據的共享也帶來其他一些問題,有的變量不能同時被兩個線程所修改,有的子程序中聲明為static的數據更有可能給多線程程序帶來災難性的打擊,這些正是編寫多線程程序時最需要注意的地方。 除了以上所說的優點外,不和進程比較,多線程程序作為一種多任務、并發的工作方式,當然有以下的優點:   1) 提高應用程序響應。這對圖形界面的程序尤其有意義,當一個操作耗時很長時,整個系統都會等待這個操作,此時程序不會響應鍵盤、鼠標、菜單的操作,而使用多線程技術,將耗時長的操作(time consuming)置于一個新的線程,可以避免這種尷尬的情況。   2) 使多CPU系統更加有效。操作系統會保證當線程數不大于CPU數目時,不同的線程運行于不同的CPU上。 3) 改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序會利于理解和修改。 ? 一、**線程標識** - 線程有ID, 但不是系統唯一, 而是進程環境中唯一有效. - 線程的句柄是pthread_t類型, 該類型不能作為整數處理, 而是一個結構. 下面介紹兩個函數: - 頭文件: <pthread.h> - 原型: int pthread_equal(pthread_t tid1, pthread_t tid2); - 返回值: 相等返回非0, 不相等返回0. - 說明: 比較兩個線程ID是否相等. ? - 頭文件: <pthread.h> - 原型: pthread_t pthread_self(); - 返回值: 返回調用線程的線程ID. 二、**線程創建** ?在執行中創建一個線程,?可以為該線程分配它需要做的工作(線程執行函數), 該線程共享進程的資源. 創建線程的函數pthread_create() - 頭文件: <pthread.h> - 原型: int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(start_rtn)(void), void *restrict arg); - 返回值: 成功則返回0, 否則返回錯誤編號. - 參數: - tidp: 指向新創建線程ID的變量, 作為函數的輸出. - attr: 用于定制各種不同的線程屬性, NULL為默認屬性(見下). - start_rtn: 函數指針, 為線程開始執行的函數名.該函數可以返回一個void?*類型的返回值,而這個返回值也可以是其他類型,并由 pthread_join()獲取 - arg: 函數的唯一無類型(void)指針參數, 如要傳多個參數, 可以用結構封裝. linux下多線程程序的編譯方法: ???????因為pthread的庫不是linux系統的庫,所以在進行編譯的時候要加上? ? ?-lpthread ???????# gcc filename -lpthread??//默認情況下gcc使用c庫,要使用額外的庫要這樣選擇使用的庫 ? 例:thread_create.c ~~~ #include <stdio.h> #include <pthread.h>? //包線程要包含 void *mythread1(void) { ?? int i; ?? for(i=0;i<100;i++) ?? { ??????printf("this is the 1st pthread,created by zieckey.\n"); ??????sleep(1); ?? } }? void *mythread2(void) { ? ? int i; for(i=0;i<100;i++) ?? { ??????printf("this is the 2st pthread,created by zieckey.\n"); ??????sleep(1); ?? } } int main() { ??? int ret=0; ????pthread_tid1,id2; ???ret=pthread_create(&id1,NULL,(void*)mythread1,NULL); ??? if(ret) ??? { ????????printf("create pthread error!\n"); ?????????return -1;? ??? } ???ret=pthread_create(&id2,NULL,(void*)mythread2,NULL); ??? if(ret) ??? { ????????printf("create pthread error!\n"); ?????????return ?-1;? ??? } ???pthread_join(id1,NULL); ???pthread_join(id2,NULL); ? ??? return 0; } 編譯步驟:gcc thread_create .c -lpthread -othread_create 例2: thread_int.c? //向線程函數傳遞整形參數 #include <stdio.h> #include <pthread.h> #include <unistd.h> void *create(void *arg) { ??? int *num; ??? num=(int *)arg; ???printf("create parameter is %d \n",*num); ??? return (void *)0; } int main(int argc,char *argv[]) { ?? pthread_t tidp; ??? int error; ??? int test=4; ??? int*attr=&test; ? ? error=pthread_create(&tidp,NULL,create,(void*)attr); ??? if(error) ???? { ???????printf("pthread_create is created is not created...\n"); ???????return -1; ??? } ?? sleep(1); ??printf("pthread_create is created...\n"); ?? return 0; } ~~~ 注:字符串,結構參數,一樣道理 三、**[線程](http://blog.csdn.net/shanzhizi)屬性** pthread_create()中的attr參數是一個結構指針,結構中的元素分別對應著新線程的運行屬性,主要包括以下幾項: ?__detachstate,表示新**線程**是否與進程中其他線程脫離同步,如果置位則新線程不能用pthread_join()來同步,且在退出時自行釋放所占用的資源。缺省為PTHREAD_CREATE_JOINABLE狀態。這個屬性也可以在線程創建并運行以后用pthread_detach()來設置,而一旦設置為PTHREAD_CREATE_DETACH狀態(不論是創建時設置還是運行時設置)則不能再恢復到? PTHREAD_CREATE_JOINABLE狀態。 ? __schedpolicy,表示新線程的調度策略,主要包括SCHED_OTHER(正常、非實時)、SCHED_RR(實時、輪轉法)和? SCHED_FIFO(實時、先入先出)三種,缺省為SCHED_OTHER,后兩種調度策略僅對超級用戶有效。運行時可以用過? pthread_setschedparam()來改變。 ? __schedparam,一個struct sched_param結構,目前僅有一個sched_priority整型變量表示線程的運行優先級。這個參數僅當調度策略為實時(即SCHED_RR或SCHED_FIFO)時才有效,并可以在運行時通過pthread_setschedparam()函數來改變,缺省為0。 ? __inheritsched,有兩種值可供選擇:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者表示新線程使用顯式指定調度策略和調度參數(即attr中的值),而后者表示繼承調用者線程的值。缺省為PTHREAD_EXPLICIT_SCHED。 ? ?__scope,表示線程間競爭CPU的范圍,也就是說線程優先級的有效范圍。POSIX的標準中定義了兩個值:? PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示與系統中所有線程一起競爭CPU時間,后者表示僅與同進程中的線程競爭CPU。目前LinuxThreads僅實現了PTHREAD_SCOPE_SYSTEM一值。 ? pthread_attr_t結構中還有一些值,為了設置這些屬性,POSIX定義了一系列屬性設置函數,包括pthread_attr_init()、 pthread_attr_destroy()和與各個屬性相關的pthread_attr_get(),pthread_attr_set()函數。 ? ??pthread_create()中,第二個參數(pthread_attr_t)為將要創建的thread屬性。通常情況下配置為NULL,使用缺省設置就可以了。但了解這些屬性,有利于更好的理解thread. 屬性對象(pthread_attr_t)是不透明的,而且不能通過賦值直接進行修改。系統提供了一組函數,用于初始化、配置和銷毀每種對象類型。 ?創建屬性: int pthread_attr_init(pthread_attr_t *attr); 創建的屬性設定為缺省設置。 ?銷毀屬性: int pthread_attr_destroy(pthread_attr_t *attr); ? **一:設置分離狀態:** **線程**的分離狀態有2種:**PTHREAD_CREATE_JOINABLE**(非分離狀態),?**PTHREAD_CREATE_DETACHED**(分離狀態) 分離狀態含義如下: 如果使用?**PTHREAD_CREATE_JOINABLE**?創建非分離線程,則假設應用程序將等待線程完成。也就是說,程序將對線程執行?**pthread_join。**?非分離線程在終止后,必須要有一個線程用 join 來等待它。否則,不會釋放該線程的資源以供新線程使用,而這通常會導致內存泄漏。因此,如果不希望線程被等待,請將該線程作為分離線程來創建。 ? 如果使用?**PTHREAD_CREATE_DETACHED**?創建分離thread**,**則表明此thread在退出時會自動回收資源和thread ID. ? Sam之前很喜歡使用分離thread.?但現在慢慢使用中覺得這樣是個不好的習慣。因為分離thread有個問題:主程序退出時,很難確認子thread已經退出。只好使用全局變量來標明子thread已經正常退出了。 另外:不管創建分離還是非分離的thread.在子thread全部退出之前退出主程序都是很有風險的。**如果主thread選擇return,或者調用exit()退出,則所有thread都會被kill掉。這樣很容易出錯。**Sam上次出的問題其實就是這個。但如果主thread只是調用pthread_exit().則僅主線程本身終止。進程及進程內的其他線程將繼續存在。所有線程都已終止時,進程也將終止。 ? intpthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 得到當前和分離狀態和設置當前的分離狀態。 ? **二:設置棧溢出保護區大小:** 棧溢出概念: 溢出保護可能會導致系統資源浪費。如果應用程序創建大量線程,并且已知這些線程永遠不會溢出其棧,則可以關閉溢出保護區。通過關閉溢出保護區,可以節省系統資源。 線程在棧上分配大型數據結構時,可能需要較大的溢出保護區來檢測棧溢出。 int pthread_attr_getguardsize(const pthread_attr_t *restrictattr,size_t *restrict guardsize); int pthread_attr_setguardsize(pthread_attr_t *attr,size_t guardsize); 設置和得到棧溢出保護區。如果guardsize設為0。則表示不設置棧溢出保護區。**guardsize**?的值向上舍入為PAGESIZE?的倍數。 ? **三:設置thread競用范圍:** 競用范圍(PTHREAD_SCOPE_SYSTEM?或?PTHREAD_SCOPE_PROCESS)指?使用?PTHREAD_SCOPE_SYSTEM?時,此線程將與系統中的所有線程進行競爭。使用?PTHREAD_SCOPE_PROCESS?時,此線程將與進程中的其他線程進行競爭。 ? int pthread_attr_getscope(const pthread_attr_t *restrict attr,int*restrict contentionscope); int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope); ? **四:設置線程并行級別:** int pthread_getconcurrency(void); int pthread_setconcurrency(int new_level); **Sam不理解這個意思。** ? **五:設置調度策略:** POSIX 標準指定?SCHED_FIFO(先入先出)、SCHED_RR(循環)或?SCHED_OTHER(實現定義的方法)的調度策略屬性。 ·?????????????????????SCHED_FIFO 如果調用進程具有有效的用戶 ID?0,則爭用范圍為系統 (PTHREAD_SCOPE_SYSTEM) 的先入先出線程屬于實時 (RT) 調度類。如果這些線程未被優先級更高的線程搶占,則會繼續處理該線程,直到該線程放棄或阻塞為止。對于具有進程爭用范圍 (PTHREAD_SCOPE_PROCESS)) 的線程或其調用進程沒有有效用戶 ID 0 的線程,請使用?SCHED_FIFO。SCHED_FIFO?基于?TS?調度類。 ·?????????????????????SCHED_RR 如果調用進程具有有效的用戶 ID?0,則爭用范圍為系統 (PTHREAD_SCOPE_SYSTEM)) 的循環線程屬于實時 (RT) 調度類。如果這些線程未被優先級更高的線程搶占,并且這些線程沒有放棄或阻塞,則在系統確定的時間段內將一直執行這些線程。對于具有進程爭用范圍 (PTHREAD_SCOPE_PROCESS) 的線程,請使用SCHED_RR(基于?TS?調度類)。此外,這些線程的調用進程沒有有效的用戶ID?0。 SCHED_FIFO?是基于隊列的調度程序,對于每個優先級都會使用不同的隊列。SCHED_RR?與 FIFO 相似,不同的是前者的每個線程都有一個執行時間配額。 ? int pthread_attr_getschedpolicy(const pthread_attr_t *restrictattr,int *restrict policy); int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); ? **六:設置優先級:** int pthread_attr_getschedparam(const pthread_attr_t *restrictattr,struct sched_param *restrict param); int pthread_attr_setschedparam(pthread_attr_t *restrict attr, ??????????????conststruct sched_param *restrict param); 比較復雜,Sam沒去研究。 ? **七:設置棧大小:** 當創建一個thread時,會給它分配一個棧空間,**線程**棧是從頁邊界開始的。任何指定的大小都被向上舍入到下一個頁邊界。不具備訪問權限的頁將被附加到棧的溢出端(第二項設置中設置)。 指定棧時,還應使用?PTHREAD_CREATE_JOINABLE?創建線程。在該線程的?pthread_join()?調用返回之前,不會釋放該棧。在該線程終止之前,不會釋放該線程的棧。了解這類線程是否已終止的唯一可靠方式是使用pthread_join。 一般情況下,不需要為線程分配棧空間。系統會為每個**線程**的棧分配指定大小的虛擬內存。 ?#ulimit -a可以看到這個缺省大小 **四、線程終止** 如果進程中的任一*[線程](http://blog.csdn.net/shanzhizi)*調用了exit,_Exit或者_exit,那么整個進程就會終止。與此類似,如果信號的默認動作是終止進程,那么,把該信號發送到線程會終止整個進程。 單個線程可以通過下列三種方式退出,在不終止整個進程的情況下停止它的控制流。 (1):從啟動例程中返回,返回值是線程的退出碼 (2):線程可以被同一進程中的其他線程取消 (3):線程調用pthread_exit() pthread_exit函數: - 原型: void pthread_exit(void *rval_ptr); - 頭文件: <pthread.h> - 參數: rval_ptr是一個無類型指針, 指向線程的返回值存儲變量. ?pthread_join函數: - 原型: int pthread_join(pthread_t thread, void **rval_ptr); - 頭文件: <pthread.h> - 返回值: 成功則返回0, 否則返回錯誤編號. - 參數: - thread: 線程ID. - rval_ptr: 指向返回值的指針(返回值也是個指針). - 說明: - 調用線程將一直阻塞, 直到指定的線程調用pthread_exit, 從啟動例程返回或被取消. - 如果線程從它的啟動例程返回, rval_ptr包含返回碼. - 如果線程被取消, 由rval_ptr指定的內存單元置為: PTHREAD_CANCELED. - 如果對返回值不關心, 可把rval_ptr設為NULL. 實例: ~~~ #include <pthread.h> #include <stdio.h> /* print process and thread IDs */ void printids(const char *s) { ???pid_t pid, ppid; ???pthread_t tid; ?? ? pid= getpid(); ???ppid = getppid(); ???tid = pthread_self(); ?? ?printf("%16s pid %5u ppid %5u tid %16u (0x%x) ", ????????????s, (unsigned int)pid, (unsigned int)ppid, ????????????(unsigned int)tid, (unsigned int)tid); } ?/* thread process */ void *thread_func(void *arg); { ???printids("new thread: "); ???return (void *)108; } ?/* main func */ int main() { ???int err; ???void *tret; /* thread return value */ ???pthread_t ntid; ?? err = pthread_create(&ntid, NULL, thread_func, NULL); ???if (err != 0) ???????perror("can't create thread"); ? ???err = pthread_join(ntid, &tret); ???if (err != 0) ???????perror("can't join thread"); ?? ?printids("main thread: "); ???printf("thread exit code: %d ", (int)tret); ???sleep(1); ?? return 0; } ~~~ 這段代碼是通過前一個實例改編的,?執行流程如下: - 首先創建一個新線程, 該線程在打印完IDs后, 返回108. - 然后用pthread_join獲取該線程返回值, 存于tret中. - 主線程打印IDs. - 主線程打印tret, 即新線程的返回值. ? 線程取消的定義: 一般情況下,線程在其主體函數退出的時候會自動終止,但同時也可以因為接收到另一個線程發來的終止(取消)請求而強制終止。 ? [線程](http://blog.csdn.net/shanzhizi)取消的語義: 線程取消的方法是向目標線程發Cancel信號,但如何處理Cancel信號則由目標線程自己決定,或者忽略、或者立即終止、或者繼續運行至Cancelation-point(取消點),由不同的Cancelation狀態決定。 線程接收到CANCEL信號的缺省處理(即pthread_create()創建線程的缺省狀態)是繼續運行至取消點,也就是說設置一個CANCELED狀態,線程繼續運行,只有運行至Cancelation-point的時候才會退出。 ? 取消點定義: 根據POSIX標準,pthread_join()、pthread_testcancel()、pthread_cond_wait()、? pthread_cond_timedwait()、sem_wait()、sigwait()等函數以及read()、write()等會引起阻塞的系統調用都是Cancelation-point,而其他pthread函數都不會引起Cancelation動作。但是pthread_cancel的手冊頁聲稱,由于LinuxThread庫與C庫結合得不好,因而目前C庫函數都不是Cancelation-point;但CANCEL信號會使線程([http://blog.csdn.net/shanzhizi](http://blog.csdn.net/shanzhizi))從阻塞的系統調用中退出,并置EINTR錯誤碼,因此可以在需要作為Cancelation-point的系統調用前后調用? pthread_testcancel(),從而達到POSIX標準所要求的目標,即如下代碼段: pthread_testcancel(); ? ???retcode = read(fd, buffer, length); ? ???pthread_testcancel();? ? 程序設計方面的考慮: 如果線程處于無限循環中,且循環體內沒有執行至取消點的必然路徑,則線程無法由外部其他線程的取消請求而終止。因此在這樣的循環體的必經路徑上應該加入pthread_testcancel()調用。即如下代碼段: ~~~ While(1) { ??? ……… ??? pthread_testcancel(); } ~~~ ? 與線程取消相關的pthread函數: intpthread_cancel(pthread_t thread):線程可以通過調用pthread_cancel函數來請求取消同一進程中的其他進程。 發送終止信號給thread線程,如果成功則返回0,否則為非0值。發送成功并不意味著thread會終止。注意pthread_cancel并不等待線程終止,它僅僅提出請求。 ?int pthread_setcancelstate(int state, int*oldstate): 設置本線程對Cancel信號的反應,state有兩種值:PTHREAD_CANCEL_ENABLE(缺省)和? PTHREAD_CANCEL_DISABLE,分別表示收到信號后設為CANCLED狀態和忽略CANCEL信號繼續運行;old_state如果不為 NULL則存入原來的Cancel狀態以便恢復。 ? int pthread_setcanceltype(int type, int*oldtype) 設置本線程取消動作的執行時機,type由兩種取值:PTHREAD_CANCEL_DEFFERED和? PTHREAD_CANCEL_ASYCHRONOUS,僅當Cancel狀態為Enable時有效,分別表示收到信號后繼續運行至下一個取消點再退出和立即執行取消動作(退出);oldtype如果不為NULL則存入原來的取消動作類型值。 ? void pthread_testcancel(void) 檢查本線程是否處于Canceld狀態,如果是,則進行取消動作,否則直接返回。 ?[http://blog.csdn.net/shanzhizi](http://blog.csdn.net/shanzhizi) 線程可以安排它退出時需要調用的函數,這與進程可以用atexit函數安排進程退出時需要調用的函數是類似的。線程可以建立多個清理處理程序。處理程序記錄在棧中,也就是說它們的執行順序與它們注冊時的順序相反。 ~~~ #include <pthread.h> void pthread_cleanup_push(void(*rtn)(void*),void *arg); void pthread_cleanup_pop(int execute); ~~~ 當線程執行以下動作時調用清理函數,調用參數為arg,清理函數的調用順序用pthread_cleanup_push來安排。 調用pthread_exit時 響應取消請求時 用非0的execute參數調用pthread_cleanup_pop時。 如果線程是通過從它的啟動例程中返回而終止的話,那么它的清理處理程序就不會被調用,還要注意清理處理程序是按照與它們安裝時相反的順序被調用的。 ? int pthread_detach(pthread_t tid); 可以用于使線程進入分離狀態。 ?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看