前言
本文將會向你介紹線程的概念,以及線程是怎么被創建的
線程概念
一、進程是承擔系統資源的基本實體,線程是cpu調度的基本單位
首先,地址空間在邏輯上相當于進程的資源窗口, 每個進程都有這樣一個資源窗口。通過地址空間+頁表獲取自身的代碼和數據
那么有沒有可能創建一個“進程”只需要創建一個pcb進程控制塊即可?(以前創建進程,需要創建地址空間,頁表,建立映射關系等等)
其實后續創建的每一個“進程”就是linux給出的線程的概念
每一個執行流占一份,每個執行流只需要占頁表的一部分,就可以看到每一個區域不同的資源塊
創建線程的量級明顯比創建進程的要低, 創建進程要從0創建,pcb地址空間構建各種映射關系,頁表,加載代碼和數據,動態庫也要加載,初始化各種代碼和數據等等
創建線程只需要創建個pcb,并沒有過多的資源申請,線程是參與資源分配的
LInux中線程的實現方案
操作系統只給線程是什么,特征是什么
具體一款os,無論底層怎么實現,只要符合給出的線程概念,就是線程,在教材里只給出線程的特征,但并不給出怎么實現線程,需要各個平臺去實現符合概念的線程
(就好比不管你讀的哪個大學,讀的清華,還是北大,都是大學生)
綜上所述:
1.線程創建更簡單,
2.線程在進程的地址空間中運行(在進程內部中運行) 主進程創建時,申請地址空間,頁表等等資源等到后續再創建線程時,就只需要創建一個pcb即可指向同一個地址空間,分配其中的資源,因此線程在進程的地址空間中運行
想必第一點你已經理解了,線程的創建更加地簡單
那么第二點該如何理解呢?
從前的進程:內部只有一個執行流(紅色框內的表示進程)
現在的進程(進程=內核數據結構+代碼和數據):內部有多個執行流(整個紅色框內表示一個進程)
其中第一個線程表示的是主線程
因此回到開頭,進程(整個紅色框所包含的)是承擔系統資源的基本實體,而線程(一個個task_struct)是cpu調度的基本單位
往后cpu看到一個pcb就執行該pcb的方法,方法只需要能在地址空間上被分配資源,cpu就執行進程代碼的一部分,訪問進程數據的一部分
因此真實在cpu上真實跑的執行流(輕量級進程—線程)就比傳統進程的量級要低一些
線程的創建
功能:創建一個新的線程
原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (start_routine)(void), void *arg);
參數:
thread:返回線程ID attr:設置線程的屬性
attr為NULL表示使用默認屬性
start_routine:是個函數地址,線程啟動后要執行的函數
arg:傳給線程啟動函數的參數 返回值:成功返回0;失敗返回錯誤碼
絕大多數函數的名字以“pthread_”打頭的函數
要使用這些函數庫,要通過引入頭文件<pthread.h> 鏈接這些線程函數庫時要使用編譯器命令的“-lpthread”選項
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
//新線程
void *ThreadRoutine(void *arg)
{const char *threadname = (const char *)arg;while(true){std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;gcnt--;sleep(1);}
}
int main()
{pthread_t tid1; //實際上pthread_t就是無符號長整形//創建線程1pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");sleep(2);//主線程while(true){std::cout << "I am main thread" << std::endl;sleep(1);}return 0;
}
通過
ps -aL 命令來查看線程id
現象:打印的pid是一樣的,說明兩個線程是屬于同一個進程里的線程,因此獲取的pid相同(理解:可以看看前文講的現在的進程是怎樣的)
LWP是用來區分線程的,全名是LIGHT WEIGHT PROCESSES輕量級進程(也就是線程)
在第一行中PID與LWP相同的就是主線程
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
void *ThreadRoutine(void *arg)
{const char *threadname = (const char *)arg;while(true){std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;gcnt--;sleep(1);}
}
int main()
{pthread_t tid1; //實際上pthread_t就是無符號長整形//創建線程1pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");sleep(2);pthread_t tid2;//創建線程2pthread_create(&tid2, NULL, ThreadRoutine, (void*)"thread 2");sleep(2);pthread_t tid3;//創建線程3pthread_create(&tid3, NULL, ThreadRoutine, (void*)"thread 3");sleep(2);//主線程while(true){std::cout << "I am main thread" << std::endl;sleep(1);}return 0;
}
現象:所有線程共享同一份地址空間(共享同一份資源,觀察:每個線程上對gcnt變量的修改在全局上有效)
小結
今日的分享就到這里啦,如果本文存在疏漏或錯誤的地方,還請您能夠指出!