該類封裝了thread的create忿等、join栖忠、detach等操作。
多線程中系統(tǒng)中將要大量使用線程操作函數(shù)。
為了擴展和維護方便庵寞,將這些函數(shù)風和鉆掛在一個類中狸相,也符合oop的理念。
muduo是這樣做的:
- 一個類捐川,來封裝需要執(zhí)行的函數(shù)脓鹃,并捕獲線程創(chuàng)建時可能的錯誤。
該類是一個struct
属拾,有一個構造函數(shù)用于初始化類中變量将谊。
有一個函數(shù),用于在線程中被調(diào)用渐白。
struct ThreadData
{
//別名
typedef boost::function<void ()> ThreadFunc;
//數(shù)據(jù)
ThreadFunc _func;//被調(diào)用的函數(shù)
string _name; //用于排錯的線程名
//構造函數(shù)
ThreadData(const ThreadFunc &func, const string &name):_func(func),_name(name){}
//被調(diào)用的函數(shù)
void runInThread()
{
//CurrentThread中的獲取當前線程尊浓。
pid_t tid=tid();
//給線程設置名字〈垦埽可以使用ps -eL查看栋齿。用于拍錯。
prctl(PR_SET_NAME,_name.c_str());
try
{
_func();
}
catch ()
{
//如果出錯襟诸,設置threadName
}
}
}
- 定義一個通用函數(shù)瓦堵,作為
pthread_create
的第三個參數(shù),這個函數(shù)將調(diào)用傳入的結構體中的一個函數(shù)歌亲。
void* start(void* i)
{
ThreadData *data=static_cast<ThreadData *>i;
data->runInThread();
delete data;//這里的應該是棧上的變量吧菇用。不需要
return NULL;
}
3。然后一類陷揪,用來控制線程的執(zhí)行惋鸥。相當于一個代理類的感覺『凡可以先初始化一個線程卦绣,等到合適的時候執(zhí)行。
class Thread
{
//別名
typedef boost::function<void ()> ThreadFunc;
private飞蚓;
ThreadFunc _func;//實際調(diào)用的函數(shù)
string _name; //對線程起的名字
bool _started;//記錄是否已經(jīng)創(chuàng)建過線程
bool _joined;//記錄是否已經(jīng)等待結束滤港,回收資源。
pthread_t _pthread; //線程id用于回收資源
public:
Thread(const ThreadFunc &func趴拧, const string &name):_func(func),_name(name),_started(false),_joided(false),_tid(0),_pthread(0);
~Thread()
{
if(_started&&!_joined)
{
pthread_detach(_pthread);
}
}
void start()
{
assert(_started);
_started=true;
ThreadData *data=new ThreadData(_func,_name);
if(pthread_create(&thread,NULL,runInThread,data))
{
_started=false;
}
delete data;
}
int joid(0
{
assert(_joided);
assert(_started);
_joined=ture;
return pthread_join(_pthread,NULL);
}
}
基礎
int pthread_create(pthread_t , const pthread_attr_t,void (func)(void), void *)
創(chuàng)建新的線程,立即執(zhí)行傳入的函數(shù)溅漾。成功返回0,否則返回錯誤編號。
在pthread.h
庫中著榴,但該庫不是c的標準哭樟凄,所以在編譯的時候需要在后面顯式的加上-lpthread
。
這是多線程的基礎兄渺。
第一個參數(shù)是線程id缝龄,pthread_t
的結構體汰现。傳入后,由函數(shù)進行填充叔壤。
第二個參數(shù)是控制參數(shù)瞎饲。可為空
第三個參數(shù)是一個函數(shù)指針(也就是函數(shù)名)炼绘。這個函數(shù)必須是void *func(void *)
嗅战,它有一個參數(shù)是void *
類型的。如果有多個參數(shù)沒那么需要在放在一個結構體中俺亮。
第四個參數(shù)傳入的參數(shù)指針或者結構體的指針驮捍。可為空
#include <pthread.h>
struct arg
{
int i;
char c;
};
//func
void *func(void *a)
{
//轉(zhuǎn)化后才可以使用
struct arg *tmp=(struct arg *)a;
}
int main()
{
//填充結構體
struct arg arg1;
arg1.i=1;
arg1.c='u'脚曾;
pthread_t tid1;
int result = pthread_create(&tid1, NULL, func, &arg1);
}
pthread_t pthread_self()和gettid()
判斷兩個線程是否相同
pthread_t
線程的id
是一個結構體东且,可已通過pthread_t pthread_self()
來返回當前線程的id。同時使用int pthread_equal(pthread_t ,pthread_t)
來判斷兩個線程id是否相同本讥,不同時返回0珊泳。
但是,這個結構體在多線程的時候有問題:不同進程中線程的線程id可能相同拷沸。所以不是作為判斷線程相同的條件色查。
gettid()
所以,常用gettid()
來判斷似乎否是同一個線程.
但是撞芍,標準c沒有實現(xiàn)這個函數(shù)秧了,所以需要使用系統(tǒng)調(diào)用。
int syscall()
系統(tǒng)調(diào)用函數(shù)序无,返回int
unistd.h
pid_t pid1=(pid_t)syscall(SYS_gettid);
同上使用上述函數(shù)來獲取tid验毡。
其中SUS_gettid
,在sys/syscall.h
中。
返回的值作為系統(tǒng)中線程中唯一的id愉镰。
其中米罚,進程中唯一線程的pid_t和通過getpid()
的返回值相同钧汹。
線程回收
等待線程執(zhí)行結束丈探,和回收資源。
線程在函數(shù)執(zhí)行結束以后拔莱,需要回收資源碗降。
線程有兩種狀態(tài)joinable
和unjoinable
。
unjoinable
下塘秦,線程所使用的資源不會被釋放讼渊,直到joinable
。
pthread_join(pthread_t,void *)
使函數(shù)變?yōu)?code>joinable
第一個參數(shù)是線程id尊剔,第二個參數(shù)可以是函數(shù)的返回值爪幻,如果是NULL
表示我們不關心函數(shù)的返回值。如果需要返回值,需要先創(chuàng)建對應的結構體挨稿,然后傳入指針仇轻,讓函數(shù)填充。
程序?qū)谠撜Z句出堵塞奶甘,直到線程執(zhí)行完畢返回篷店。即使有很多該函數(shù)也會依次執(zhí)行。
int pthread_atfork(void (prepare)(void), void (parent)(void), void (*child)(void));
pthread_detach(pthread_t)
即使函數(shù)沒執(zhí)行完也可以使用該函數(shù)制定線程的狀態(tài)
執(zhí)行該函數(shù)后臭家,線程中函數(shù)運行結束后直接釋放所消耗的資源疲陕。
prctl()
可以設置和獲取線程的名字
prctl(PR_SET_NAME,"name");
prctl(PR_GET_NAME,buf);//如果沒設置那么獲取的是值是`getid`
為fork和pthread注冊函數(shù)
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
pthread_atfork()在fork()之前調(diào)用,當調(diào)用fork時钉赁,內(nèi)部創(chuàng)建子進程前在父進程中會調(diào)用prepare蹄殃,內(nèi)部創(chuàng)建子進程成功后,父進程會調(diào)用parent 橄霉,子進程會調(diào)用child窃爷。