1.線程概念
在一個程序里的一個執行路線就叫做線程(thread)。更準確的定義是:線程是“一個進程內部的控制序列。在linux中,由于線程和進程都具有id,都需要調度等等相似性,因此都可以用PCB來描述和控制,線程含有PCB,沒有獨立的地址空間,和進程內的其他線程共享地址空間。如下圖:
從資源的角度上看,進程是資源分配的基本單位,線程是cpu調度的基本單位。每一個控制線程pcb,我們都可以看成是執行流,執行流可以是線程,也可以是只有一個線程的進程,在Linux中,所有執行流我們都可以看成輕量級進程(LWP)。
2.線程控制函數
首先,我們要了解Linux沒有真正意義上的線程,所有執行流都是LWP,因此,為了滿足用戶對線程使用的需求,Linux的線程庫對LWP的接口進行了封裝,我們把庫里封裝好的線程稱為用戶級線程。
1.pthread_create創建線程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
第一個參數是輸出型參數,輸出新線程的用戶級線程id,參數2:設置線程的屬性,參數3:返回值和參數都為void* 類型的函數指針,參數4:函數參數。創建線程,執行傳入的函數。
2.pthread_join等待線程
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);
第一個參數是要等的線程id,第二個是線程執行后返回值?。
3.?pthread_exit,pthread_cancel,pthread_self()?
int pthread_exit()線程退出,exit()是進程退出。
int pthread_cancel(pthread_t thread)讓某個進程退出
pthread pthread_self() 用于獲取用戶態線程的tid
4.代碼
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <unistd.h>
#include <cstdlib>
#include<time.h>
#include <pthread.h> // 原生線程庫的頭文件
using namespace std;// pthread_create(pthread_t &tid, nullptr, handlerTask, td);創建線程的接口
//pthread_join(tid, &ret);線程等待
// pthread_exit()線程退出
//pthread_cancel(tid)取消線程
pthread_self() 用于獲取用戶態線程的tidvoid * handlerTask(void* args)
{string s1=(const char*)args;sleep(10);cout<<"我是"<<s1<<" pid 是 "<<getpid()<<endl;cout<<"我的用戶級線程id是"<<pthread_self()<<endl;string* s2=new string("haha");pthread_exit(s2);}int main()
{cout<<"我是主線程"<<" pid 是 "<<getpid()<<endl;cout<<"我的用戶級線程id是"<<pthread_self()<<endl;const char* s1="新線程";pthread_t tid;pthread_create(&tid, nullptr, handlerTask, (void*)s1);cout<<"新進程用戶級id是"<<tid<<endl;void *ret=nullptr;pthread_join(tid, &ret);cout<<"結果為"<<*((string*)ret)<<endl;
}
makefile 文件(注意一定要鏈接pthread庫)
test1:test1.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f test1
運行結果:
5.進程分離
- 默認情況下,新創建的線程是joinable的,線程退出后,需要對其進行pthread_join操作,否則無法釋放資源,從而造成系統泄漏。
- 如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時,自動釋放線程資源。?
int pthread_detach(pthread_t thread)
可以是線程組內其他線程對目標線程進行分離,也可以是線程自己分離.
pthread_detach(pthread_self());
3.用戶級進程的實現
在共享區上由pthead動態庫來維護,封裝了LWP,其中用戶級進程的id就是虛擬地址。?
4.資源問題
1.線程私有的:
- 線程的硬件上下文(cpu寄存器的值)
- 線程的獨立棧結構
- 線程id
- 信號屏蔽字
- ?errno 信號屏蔽字
- 調度優先級
2.線程共享的
- 內存和地址空間(代碼和全局數據)
- 文件描述符表
- 每種信號的處理方式(SIG_ IGN、SIG_ DFL或者自定義的信號處理函數)
- 當前工作目錄
- 用戶id和組id
5.進程線程的優缺點
線程的優點
- 創建一個新線程的代價要比創建一個新進程小得多(線程的地址內存和地址空間是共享的,只需要創間pcb)
- 與進程之間的切換相比,線程之間的切換需要操作系統做的工作要少很多(線程切換時由于數據共享,cache不需要重新加載,而進程切換需要重新加載)。
- 線程占用的資源要比進程少很多
- 能充分利用多處理器的可并行數量
- 在等待慢速I/O操作結束的同時,程序可執行其他的計算任務
- 計算密集型應用,為了能在多處理器系統上運行,將計算分解到多個線程中實現
- I/O密集型應用,為了提高性能,將I/O操作重疊。線程可以同時等待不同的I/O操作。