線程和進程
以前我們要同時跑多個程序,可以通過fork()多個子進程,然后通過系統函數進行程序的替換,但是創建進程代價大,不僅要拷貝一份父進程的地址空間,頁表,文件表述符表等。但是線程不需要因為是進程的執行流,共享同個地址空間,頁表,只需讓不同線程執行不同的代碼塊(函數就可以了)。
一、線程函數接口
它們的返回值都比較統一,成功就返回0,失敗就返回錯誤碼
(1)線程創建
第一個參數類型是我們在定義的一個pthread_t類型的變量指針,通過它我們可以拿到?用戶識別的線程id。第二個參數設置為空。第三個參數是函數指針,第四個是我們要傳入線程執行函數的參數,由于它的類型是void*,我們可以傳入任意類型
(2)線程等待?
線程和進程一樣,雖然是一個進程的地址空間的執行流,但是也要進行等待回收,不然會造成類似內存泄漏 問題。retval是輸出型參數,通過它可以拿到線程退出信息(簡單說就是線程執行函數的返回值)。
(3)線程中止
?進程有退出碼,線程沒有,只有我們自己寫的返回值,既用pthread_exit()返回,或者直接return返回自定義的碼(由于返回值類型是void*,要強轉),不建議用exit()因為會造成主線程退出,主線程退出了,進程資源就釋放了,所有線程就跟著退出了。通常這返回值信息會被線程等待函數pthread_join()拿到。
(4)線程分離?
?以前子進程退出如果父進程不進行等待,我們可以自定義捕捉函數對子進程發出的退出信號進行忽略,不會有僵尸進程。線程也可以通過分離,讓主線程不用主動對它進行等待,就算線程退出也不會有類型內存泄漏問題。注意的是,線程分離只是一種工作狀態,它和沒分離的線程幾乎一樣,只是不用等待了。
二,多線程的創建
pthread_create函數參數由于是void*,我們就可以傳任意類型的對象
makefile
test:classpthreads.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f test
?classpthreads.cc
#include<iostream>
using namespace std;
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include <sys/types.h>
#include<vector>namespace ljh{
class Task{
public:
Task():datex(0),datey(0)
{}
void SetDate(int x,int y)
{datex=x;datey=y;
}
int Excute()
{return datex+datey;
}
~Task()
{}private:int datex;int datey;};
class threaddate:public Task
{
public:threaddate(int x,int y,char* threadname ):_x(x),_y(y),_threadname(threadname){s.SetDate(_x,_y);}string getname(){return _threadname;}int run(){s.Excute();}private:
string _threadname;
int _x;
int _y;
Task s;};
class Result{
public:
void SetResult(int result,string& threadname)
{_result=result;_threadname=threadname;}
void Print()
{cout<<"result:"<<_result<<"threadname"<<_threadname<<endl;}
private:int _result;string _threadname;
};}using namespace ljh;
void* handlerTask(void*p)
{threaddate* td=static_cast<threaddate*>(p);
string name=td->getname();
Result* result=new Result();
int ret=td->run();
result->SetResult(ret,name);
delete td;
sleep(2);
return result;}vector<Result*> ret;
vector<pthread_t> pthreadname;
int main()
{for(int i=0;i<5;i++)//創建5個線程{char* name=new char[64];pthread_t id;snprintf(name,sizeof(name),"Thread_%d",i+1);threaddate* p=new threaddate(2,6,name);pthread_create(&id,nullptr,handlerTask,p);pthreadname.push_back(id);}for(auto e:pthreadname){ void* s=nullptr;//返回值,void*pthread_join(e,&s);//線程等待回收ret.push_back((Result*)s);}return 0;
}
三.創建的線程和主線程之間關系
1.多線程只是主線程的執行流,主線程main退出,子進程也會退出,所以我們必須讓主線程最后退出
2.創建的新線程和主線程,哪個先運行,這個取決與調度器。
線程共享和私有
(1)共享:代碼和全局數據和進程文件描述符表
因為它們擁有同一塊地址空間
(2)私有:線程的硬件上下文數據(cpu寄存器的值),線程的獨立棧結構。對于多進程來說,線程的上下文數據比進程少,所以也叫線程為輕量級進程。
我們可以用命令查看(ps -aL | grep? xxx).對于棧來說,不同線程可以分為進程地址空間的棧空間還有線程獨立的棧,訪問全局數據就時訪問進程地址空間主棧,在線程執行函數里面變量之類的就是線程獨立的棧。
驗證:創建3個線程,定義一個全局變量vale,還有線程執行函數的n,不同的線程打印全局vale地址是相同,n的地址卻是不同的。