線程輪詢阻塞,由系統調度喚醒,實時性不高。
線程阻塞的方式好多,不過根本原因是調用能引起調度的函數即可,其他的工作就讓系統調度來完成。
readThread{ while(TRUE){ sleep(3); //數據處理 } }
最簡單的就是使用sleep函數讓線程進入休眠。等休眠結束后,線程由“阻塞狀態”進入“就緒狀態”,期間就需要系統根據不同線程間的nice值來評判運行的優先級。顯然這種方式的實時性不高,而且還可能被系統中斷打斷的可能。不過對於我們而言,這種狀態已經足夠了。因為現在的系統都是微秒級別,基本差別不到差別。而且對於使用這種方式的用戶,也不需要很高的實時性要求。足夠我們使用了。
再次說到,內核空間的用法跟用戶空間很相似。這種使用方法,在內核也有相應的辦法實現的,除了像上面的使用方法外,內核還可以借助schedule的系統調度來完成,這種方式直接使用系統調度,更為簡潔。而且對於開一個調度和開一線程,對於內核而言,原理性都是一樣的。所以在內核里面的做法,是建議使用schedule的方式,而且有需要的話,還可以使用schedule_work_on和schedule_delayed_owrk_on來指定執行的CPU,資源由我們自動分配。
首先說明一下,在Linux編寫多線程程序需要包含頭文件pthread.h。也就是說你在任何采用多線程設計的程序中都會看到類似這樣的代碼: #include <pthread.h> 當然,進包含一個頭文件是不能搞定線程的,還需要連接libpthread.so這個庫,因此在程序連接階段應該有類似這樣的指令: gcc program.o -o program -lpthread
頭文件: <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庫,要使用額外的庫要這樣選擇使用的庫
線程的合並與分離 我們首先要明確的一個問題就是什么是線程的合並。從前面的敘述中讀者們已經了解到了,pthread_create()接口負責創建了一個線程。
那么線程也屬於系統的資源,這跟內存沒什么兩樣,而且線程本身也要占據一定的內存空間。
眾所周知的一個問題就是C或C++編程中如果要通過malloc()或new分配了一塊內存,就必須使用free()或delete來回收這塊內存,否則就會產生著名的內存泄漏問題。
既然線程和內存沒什么兩樣,那么有創建就必須得有回收,否則就會產生另外一個著名的資源泄漏問題,這同樣也是一個嚴重的問題。那么線程的合並就是回收線程資源了。 線程的合並是一種主動回收線程資源的方案。當一個進程或線程調用了針對其它線程的pthread_join()接口,就是線程合並了。
這個接口會阻塞調用進程或線程,直到被合並的線程結束為止。當被合並線程結束,pthread_join()接口就會回收這個線程的資源,並將這個線程的返回值返回給合並者。 與線程合並相對應的另外一種線程資源回收機制是線程分離,調用接口是pthread_detach()。
線程分離是將線程資源的回收工作交由系統自動來完成,也就是說當被分離的線程結束之后,系統會自動回收它的資源。
因為線程分離是啟動系統的自動回收機制,那么程序也就無法獲得被分離線程的返回值,這就使得pthread_detach()接口只要擁有一個參數就行了,那就是被分離線程句柄。 線程合並和線程分離都是用於回收線程資源的,可以根據不同的業務場景酌情使用。不管有什么理由,你都必須選擇其中一種,否則就會引發資源泄漏的問題,這個問題與內存泄漏同樣可怕。
線程取消(pthread_cancel)
功能:調用線程終止同進程中,其他的線程,調用該方法后,被終止的線程並不一定立馬被終止,只有在下次系統調用或調用了pthread_testcancel()方法后,才真正終止線程。
創建線程
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<pthread.h> #include<unistd.h> #include<sys/types.h> char message[50] = "THREAD_TEST"; void* thread_func(void *arg); int main(){ pthread_t t_thread; void *thread_result; int res; res = pthread_create(&t_thread, NULL, thread_func, (void*)message); if(res != 0){ perror("線程創建失敗!"); exit(EXIT_FAILURE); } printf("wait for the thread!\n"); pthread_join(t_thread, &thread_result); printf("線程已結束,返回值為%s\n", (char*)thread_result); printf("message的值為%s\n", message); free(thread_result); exit(EXIT_SUCCESS); } void* thread_func(void *arg){ printf("線程正在運行,參數為%s\n", (char*)arg); sleep(3); strcpy(message, "線程修改"); char* buf = (char*)malloc(strlen("線程執行完畢!")); strcpy(buf, "線程執行完畢!"); pthread_exit(buf); }
取消線程
#include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> void *thread_func(void *arg){ int res; res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if(res != 0){ perror("設置線程取消失敗"); exit(EXIT_FAILURE); } if((res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) != 0){ perror("設置線程取消類型失敗!"); exit(EXIT_FAILURE); } printf("子線程正在運行!\n"); for(int i = 0; i < 10; i++){ sleep(1); printf("子線程正在運行!\n"); } pthread_exit(EXIT_SUCCESS); } int main(){ int res; pthread_t thread; if((res = pthread_create(&thread, NULL, thread_func, NULL)) != 0){ perror("線程創建失敗!"); exit(EXIT_FAILURE); } sleep(3); printf("取消線程!\n"); if((res = pthread_cancel(thread)) != 0){ perror("取消線程失敗!"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
引用鏈接:https://blog.csdn.net/hbk320/article/details/49666757
https://www.cnblogs.com/jiu0821/p/6707912.html
https://www.cnblogs.com/fnlingnzb-learner/p/6962868.html
https://www.jianshu.com/p/212dd2a052f3
https://www.cnblogs.com/lijunamneg/archive/2013/01/25/2877211.html