C++11線程庫
C++11
也提供了對應的線程庫,在頭文件<thread>
中;C++11
將其封裝成thread
類,通過類實例化出對象,調用類內成員方法進行線程控制。
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;
void func()
{int cnt = 3;while(cnt--){cout<<"thread : "<<cnt<<endl;sleep(1); }
}
int main()
{thread td(func);//創建線程sleep(5);td.detach();//線程分離td.join();//線程等待return 0;
}
線程封裝
C++11
實現的線程thread
是對pthread
庫的封裝,這里也對pthread
庫做簡單封裝;
首先要封裝實現一個thread
類,其中要包括成員變量:線程ID、分離狀態(detach
)、運行狀態(runing
)、返回值、線程名稱等等
namespace mypthread
{class thread{public:private:pthread_t _tid;std::string _name;bool _detach;bool _runing;void* retval;};
}
構造函數(創建線程)
像C++
thread一樣,在創建對象時就將線程要執行的方法傳入,那在thread
類中,就要存在一個成員變量func
(沒有參數、沒有返回值的)
這里就要使用
C++11
語法:function
包裝器
using func = std::function<void(void)>;
這樣在類內定義void(void)
類型的成員變量。
但是,我們知道,在調用pthread_create
創建線程時,要傳遞的函數類型是(void*(void*))類型的,所以就還要存在一個void*(void*)
類型的函數;我們可以將該方法實現成靜態成員函數
但是,這個函數還要可以訪問thread
類內成員func
,靜態成員函數沒有隱藏的this
指針,這里可以將this
作為參數傳遞給線程要調用的方法(pthread_create
第四個參數)
namespace mypthread
{static int count = 1;using func = std::function<void(void)>;class thread{static void *routine(void *msg){// 傳遞的是this指針thread *td = static_cast<thread *>(msg);std::cout << td->_name << std::endl;// 調用funtd->_fun();return (void *)100;}public:thread(func fun) : retval(nullptr), _fun(fun), _detach(false){_name = "thread-" + std::to_string(count);count++;int n = pthread_create(&_tid, nullptr, routine, (void *)this);if (n != 0){std::cerr << "pthread_create" << std::endl;}_runing = true;}private:pthread_t _tid;std::string _name;bool _detach;bool _runing;void *retval;func _fun;};
}
這里為了方便測試,存在一個count
計數器,為了生成線程名稱_name
。
線程分離
在創建線程之后,我們可以設置線程分離;
void Detach(){if(_detach)return;pthread_detach(_tid);_deatch = true;}
線程取消
我們可以調用pthread_cancel
來取消線程;
bool Cancel(){if (_runing == false)return;int n = pthread_cancel(_tid);if (n != 0){std::cerr << "pthread_cancel" << std :: endl;return false;}return true;}
線程等待
新創建的線程在運行結束后,需要進行線程等待;這里實現就直接調用pthread_join
阻塞等待線程;然后將線程的返回值放到_retval
中。
void Join(){pthread_join(_tid, &_retval);}
析構函數(回收線程)
對pthread
庫進行面向對象封裝,在thread
析構函數中,就要調用線程取消Cancel
,然后調用Join
回收線程并獲取線程的返回值。
~thread(){Cancel();Join();}
測試thread
using namespace mypthread;
void test()
{int cnt = 3;while (cnt--){std::cout << "new thread : " << cnt << std::endl;sleep(1);}
}
int main()
{thread td(test);sleep(5);return 0;
}
這樣在main
函數中,就算我們沒有顯示調用Join
等待,在線程thread
對象出了作用域后,自動調用析構函數從而調用Cancel
和Join
回收線程。
番外
對于線程封裝,這里實現了另外一種版本:
在創建thread
對象之后并不會立即創建新線程,而是調用Start
才會創建新線程;
此外我們可以在沒有創建線程時設置detach
分離狀態,也可以在線程運行時設置detach
分離狀態;
namespace mythread
{static int count = 1;using func_t = std::function<void()>;class Thread{static void *rontinue(void *args){Thread *pt = static_cast<Thread *>(args);pt->_fun();return (void*)pt->_name.c_str();}void EnableDetach() { _detach = true; }void EnableRuning() { _runing = true; }public:Thread(func_t fun) : _tid(-1), _detach(false), _runing(false), _fun(fun), _retval(nullptr){_name = "thread- " + std::to_string(count);count++;}void Start(){if (_runing)return;// 創建線程int n = pthread_create(&_tid, nullptr, rontinue, this);if (n != 0){std::cerr << "pthread_create" << std::endl;exit(1);}EnableRuning();Detach();}void Detach(){if (_detach){if (_runing){pthread_detach(_tid);}EnableDetach();}}void Cancel(){if (_runing){pthread_cancel(_tid);}_runing = false;}void Join(){if (_detach)return;pthread_join(_tid, &_retval);}std::string GetName(){return _name;}private:pthread_t _tid; // 線程idstd::string _name; // 線程名bool _detach; // 分離狀態bool _runing; // 運行狀態func_t _fun; // 線程執行函數void *_retval; // 返回值};
}
簡單總結:
本篇文章對
pthread
庫做了簡單封裝,實現了簡單的thread
類。