線程詳解

程序是編譯好的二進制文件,在磁盤上,不佔用系統資源。
進程是運行的程序,佔用系統資源,在內存中執行。
線程是輕量級的進程,本質任是進程(在Linux環境下)
線程和進程的區別和聯繫:
(1)進程有獨立的地址空間,擁有PCB
(2)線程也有自己的PCB,但是沒有獨立的地址空間
區別:是否共享地址空間,例如,進程a.out有自己的0到4G的地址空間,當它調用pthead_create創建線程的時候,線程的PCB也是存在a.out的0到4G的地址空間中的,此時進程a.out就變成了線程,和它新創建出來的線程共享地址空間,但是有各自的PCB。
Linux下,線程是最小的執行單位,進程是最小的分配資源的單位。
爲了更好的解釋這句話,先引入以下幾個知識點:
單道程序設計:cpu在同一時間只能執行一個任務
多道程序設計:進程分爲多個時間片,輪流使用cpu資源
在這裏插入圖片描述
**併發:**一個時間段中有多個進程都處於已啓動運行到運行完畢之間的狀態,但任一個時刻點上仍只有一個進程在運行。可以看成兩個或多個事件在同一時間間隔發生,如以正常速度的N倍吃一口飯喝一口水。
**並行:**指兩個或者多個事件在同一時刻發生,如吃飯的時候可以邊吃飯邊打電話。
總之,加入有1萬個請求同時過來,很明顯不可能真正的同時去處理這1萬個請求,如果這臺機器的處理器有4個核心,不考慮超線程,那麼我們認爲同時會有4個線程在跑。也就是說,併發訪問數是1萬,而底層真實的並行處理的請求數是4。所以,併發只是分時複用,由於計算機執行速度快,可以把它看做宏觀上的並行,微觀上的串行,就是上面的多道程序設計模型,並行是多核處理器上真正的同時執行。
現在回到上面那句話的理解,如下圖所示,當沒有紅線指向的區域時,三個進程在CPU中輪流執行,當第一個進程變成線程後,也就是紅線指向的地方,CPU分配時間的時候,把最左邊的當做五份來分,也就是原來CPU把自己分成三份,現在分成七份,最左邊的線程佔五份,所以它在相同的時間內能獲得更多的時間輪片,這也就是爲什麼多線程效率更高的原因。因此,線程是最小的執行單位。其次,那五個線程共享地址共享,因此分配資源的時候是按照進程劃分的。
在這裏插入圖片描述
此外,從內核角度看,進程和線程是一樣的(因爲內核以PCB作爲區分),都有各自不同的PCB。
ps -Lf PID可以查看指定程序的線程數,下圖LWP是線程號,是CPU分配時間片的依據,不是線程ID。
ps -aux 查看所有運行的程序的PID等信息。
在這裏插入圖片描述
要創建一個線程,必須先有進程,那麼,同一個虛擬地址空間中的線程之間共享那些資源,獨享那些資源?
共享:
(1)文件描述符表、打開的文件
(2)每種信號的處理方式
(3)當前工作目錄
(4)用戶ID和組ID
(5)內存地址空間(.text .data .bss heap 除棧空間)
獨享:
(1)線程id
(2)處理器現場和棧指針(內核棧)
(3)獨立的棧空間(用戶空間棧,如函數調用棧幀)
(4)error變量
(5)信號屏蔽字
(6)調度優先級
線程優缺點:
優點:提高程序併發性,開銷小,數據通信共享數據方便
缺點:庫函數不穩定(進程中用的函數都是系統調用,而線程中使用的大部分都是庫函數,穩定性相對進程低),調試編寫困難(gdb不支持),對信號支持不好
創建n個線程實例

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

void *thrd_func(void *arg){
    int i = (int)arg;
    sleep(i);
    printf("%dth thread: thread id = %lu, pid = %u\n",i,pthread_self(),getpid());
    return NULL;
}

int main(void){
    pthread_t tid;
    int ret,i;

    for(i = 0; i < 5; i++){
        //區別於進程,線程創建成功後會去執行自己的代碼,即main函數裏面的代碼都
是屬於主控線程的,所以不會出現創建出來的線程又會創建線程的循環
        ret = pthread_create(&tid,NULL,thrd_func,(void *)i);
        if(ret != 0){
            fprintf(stderr,"pthread_create error:%s",strerror(ret));
            exit(1);
        }
    }

    sleep(i);//防止進程在線程之前退出
    return 0;
}

注意,gcc編譯的時候需要帶上參數-lpthread
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章