LinuxC高级编程——线程
LinuxC高級編程——線程
 
宗旨:技術的學習是有限的,分享的精神是無限的。
 
 
一、線程基礎
? ? ? ? main函數和信號處理函數是同一個進程地址空間中的多個控制流程,多線程也是如 此,但是比信號處理函數更加靈活,信號處理函數的控制流程只是在信號遞達時產生,在處理完信 號之后就結束,而多線程的控制流程可以長期并存,操作系統會在各線程之間調度和切換,就像在 多個進程之間調度和切換一樣。由于同一進程的多個線程共享同一地址空間,因此Text Segment、 Data Segment都是共享的,如果定義一個函數,在各線程中都可以調用,如果定義一 個全局變量,在各線程中都可以訪問到,除此之外,各線程還共享以下進程資源和環境:
【文件描述符表 每種信號的處理方式( SIG_IGN、 SIG_DFL或者自定義的信號處理函數) 當前工作目錄 用戶id和組id 但有些資源是每個線程各有一份的: 線程id 上下文,包括各種寄存器的值、程序計數器和棧指針 棧空間errno變量 信號屏蔽字 調度優先級】
? ? ? ? 在Linux上線 程函數位于libpthread共享庫中,因此在編譯時要加上-lpthread選項。
?
二、線程控制
1、pthread_create
——創建線程
(1)函數原型
#include <pthread.h> typedef unsigned long int pthread_t; int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);(2)函數參數
?????? thread:存儲線程ID(指向線程ID的指針)
?????? restrict:設置線程屬性,一般情況下為NULL
?????? start_routine:線程運行的代碼起始地址
?????? arg:運行函數的參數地址
(3)返回值
?????? 返回值:成功返回0,失敗返回錯誤號。之前學過的系統函數都是成功返回0,失敗返回-1,而錯誤號保存在全局變量errno中,而pthread庫的函數都是通過返回值返回錯誤號,雖然每個線程也都有一個errno,但這是為了兼容其它函數接口而提供的, pthread庫本身并不使用它,通過返回值返回錯誤碼更加清晰。
? ? ? ? 在一個線程中調用pthread_create()創建新的線程后,當前線程從pthread_create()返回繼續往下執 行,而新的線程所執行的代碼由我們傳給pthread_create的函數指針start_routine決 定。start_routine函數接收一個參數,是通過pthread_create的arg參數傳遞給它的,該參數的類 型為void *,這個指針按什么類型解釋由調用者自己定義。 start_routine的返回值類型也是void*,這個指針的含義同樣由調用者自己定義。 start_routine返回時,這個線程就退出了,其它線程可以調用pthread_join得到start_routine的返回值,類似于父進程調用wait(2)得到子進程的退出狀態。
? ? ? ? pthread_create成功返回后,新創建的線程的id被填寫到thread參數所指向的內存單元。我們知道 進程id的類型是pid_t,每個進程的id在整個系統中是唯一的,調用getpid(2)可以獲得當前進程 的id,是一個正整數值。線程id的類型是thread_t,它只在當前進程中保證是唯一的,在不同的系 統中thread_t這個類型有不同的實現,它可能是一個整數值,也可能是一個結構體,也可能是一個 地址,所以不能簡單地當成整數用printf打印,調用pthread_self(3)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h>pthread_t ntid;void printids(const char *s) {pid_t pid;pthread_t tid;656pid = getpid();tid = pthread_self();printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid,(unsigned int)tid, (unsigned int)tid); } void *thr_fn(void *arg) {printids(arg);return NULL; } int main(void) {int err;err = pthread_create(&ntid, NULL, thr_fn, "new thread: ");if (err != 0){fprintf(stderr, "can't create thread: %s\n",strerror(err));exit(1);}printids("main thread:");sleep(1);return 0; }<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">?</span>2、終止線程
如果需要只終止某個線程而不終止整個進程,可以有三種方法:
(1)從線程函數return。這種方法對主線程不適用,從main函數return相當于調用exit。
(2)一個線程可以調用pthread_cancel終止同一進程中的另一個線程。
(3) 線程可以調用pthread_exit終止自己。
(1)函數原型
#include <pthread.h> void pthread_exit(void *value_ptr);(2)函數參數
?????? value_ptr:線程退出狀態,其它線程可以調用pthread_join獲得這個 指針。
(3)返回值——無
? ? ? ? 需要注意,pthread_exit或者return返回的指針所指向的內存單元必須是全局的或者是用malloc分配的,不能在線程函數的棧上分配,因為當其它線程得到這個返回指針時線程函數已經退出了。
?
3、pthread_join
——調用該函數的線程將掛起等待,直到id為thread的線程終止
(1)函數原型
#include <pthread.h> int pthread_join(pthread_t thread, void **value_ptr);(2)函數參數
?????? thread:線程ID
?????? value_ptr:
?????? value_ptr:線程退出狀態
(3)返回值
? ? ? ? 成功返回0,失敗返回錯誤號
? ? ? ? 通過pthread_join得到的終止狀態是不同的,總結如下: 如果thread線程通過return返回, value_ptr所指向的單元里存放的是thread線程函數的返回值。 如果thread線程被別的線程調用pthread_cancel異常終止掉,value_ptr所指向的單元里存放的是常數PTHREAD_CANCELED。 如果thread線程是自己調用pthread_exit終止的, value_ptr所指向的單元存放的是傳 給pthread_exit的參數。 如果對thread線程的終止狀態不感興趣,可以傳NULL給value_ptr參數。?
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h>void *thr_fn1(void *arg) {printf("thread 1 returning\n");return (void *)1; }void *thr_fn2(void *arg) {printf("thread 2 exiting\n");pthread_exit((void *)2); }void *thr_fn3(void *arg) {while(1){printf("thread 3 writing\n");658sleep(1);} }int main(void) {pthread_t tid;void *tret;pthread_create(&tid, NULL, thr_fn1, NULL);pthread_join(tid, &tret);printf("thread 1 exit code %d\n", (int)tret);pthread_create(&tid, NULL, thr_fn2, NULL);pthread_join(tid, &tret);printf("thread 2 exit code %d\n", (int)tret);pthread_create(&tid, NULL, thr_fn3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, &tret);printf("thread 3 exit code %d\n", (int)tret);return 0; }4、pthread_detach
? ? ? ? ——線程也可以被置為detach狀態,這樣的線程一旦終止就立刻回收它占用的所有資源,而不保留終止狀態。不能對一個已經處于detach狀態的線程調用pthread_join,這樣的調用將返回EINVAL。 對一個尚未detach的線程調用pthread_join或pthread_detach都可以把該線程置為detach狀態,也就是說,不能對同一線程調用兩次pthread_join,或者如果已經對一個線程調用了pthread_detach就不能再調用pthread_join了。
(1)函數原型
#include <pthread.h> int pthread_detach(pthread_t tid);(2)函數參數
?????? tid:線程id
(3)返回值
? ? ? ?成功返回0,失敗返回錯誤號
總結
以上是生活随笔為你收集整理的LinuxC高级编程——线程的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: lacp静态和动态区别_LACP基础
- 下一篇: android 动态壁纸 例子,andr
