/*
源码来自vs2017
*/
using _Thrd_id_t = unsigned int;
struct _Thrd_t { // thread identifier for Win32
void* _Hnd; // Win32 HANDLE
_Thrd_id_t _Id; //保存线程id
};
class thread { // class for observing and managing threads
public:
class id;
using native_handle_type = void*;
thread() noexcept : _Thr{} {}
private:
...
template
void _Start(_Fn&& _Fx, _Args&&... _Ax) {...}
public:
template , thread>, int> = 0>
_NODISCARD_CTOR explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
_Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}
thread(thread&& _Other) noexcept : _Thr(_STD exchange(_Other._Thr, {})) {}
thread& operator=(thread&& _Other) noexcept {...}
thread(const thread&) = delete;
thread& operator=(const thread&) = delete;
~thread() noexcept {...}
void swap(thread& _Other) noexcept {...}
//判断线程是否可以被join,实际判断线程ID是否为0
_NODISCARD bool joinable() const noexcept {...}
//等待线程
void join() {...}
//线程分离
void detach() {...}
//获取线程ID
_NODISCARD id get_id() const noexcept;
//获取win32句柄
_NODISCARD native_handle_type native_handle() noexcept /* strengthened */ { // return Win32 HANDLE as void *
return _Thr._Hnd;
}
//检测硬件并发特性
_NODISCARD static unsigned int hardware_concurrency() noexcept {
return _Thrd_hardware_concurrency();
}
private:
_Thrd_t _Thr;
};
常用的接口有: 构造函数, joinable(), join(),detach(),get_id();
void threadFunc() {
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "thread ID: " << std::this_thread::get_id() << std::endl;
}
int main()
{
std::thread myThread(threadFunc);
cout << myThread.get_id() << endl;
if (myThread.joinable()) {
//myThread.detach(); 线程分离,只能看到 main ID 打印
myThread.join(); //都能看见ID打印
}
return 0;
}
当线程传递参数时,需特别注意与detech()一起使用时出现的问题;
void threadFunc1(const int& i, char* buf)
{
std::cout << "&i=" << &i << " &buf=" << (void *)buf << std::endl;
&i = 0000023590C30A98 & buf = 00000037DD95FA58
}
int main()
{
int val = 10;
int &reVal = val;
char buf[] = "this is test";
std::thread myThread(threadFunc1, val,buf);
cout << "main &val=" << &val << " &buf=" << &buf << endl;
//main &val=00000037DD95FA14 &buf=00000037DD95FA58
if (myThread.joinable()) {
//myThread.join(); //没啥问题
myThread.detach();
}
return 0;
}
当使用引用和指针作为线程参数传递时, 经过打印知 i实际为值传递, 而buf与main地址相同;
那么就可能存在detach()时,主线程已经跑完且buf地址已经失效,而线程中可能还在使用该地址;
避坑:
// const string& buf建议使用引用,省一次构造
void threadFunc2(const int i, const string& buf)
{
std::cout << i << " "<< buf.c_str() << std::endl;
}
int main()
{
int val = 10;
int &reVal = val;
char buf[] = "this is test";
//直接将其转为string对象,且要保证在main中就转成功;
//即使这里是引用, 也能够保证两者地址不一样;
std::thread myThread(threadFunc2, val,string(buf));
if (myThread.joinable()) {
//myThread.join(); //没啥问题
myThread.detach();
}
return 0;
}
//不加&多产生一次拷贝构造,建议都加上;
void threadFunc3(const A &buf)
{
std::cout << buf.m_i << endl;
}
int main()
{
A objA(10);
std::thread myThread(threadFunc3, objA);
//就想传递引用呢, 加上std::ref即可
//std::thread myThread(threadFunc3, std::ref(objA));
if (myThread.joinable()) {
myThread.join();
}
return 0;
}
void threadFunc4(std::unique_ptr ptr)
{
}
int main()
{
std::unique_ptr myPtr(new int(10));
//传递后myPtr指向空了 不能使用detech,因为主线程先执行完,myPtr指向的对象被释放了;
std::thread myThread(threadFunc4, std::move(myPtr)); // 移动智能指针到线程
if (myThread.joinable()) {
myThread.join();
//myThread.detach();//一定不能是detach
}
return 0;
}
class A
{
public:
int m_i;
//类型转换构造函数,可以把一个Int转成类对象;
A(int a) :m_i(a) { cout << "构造" << this << "thread id= " << std::this_thread::get_id() << endl; }
A(const A& a) :m_i(a.m_i) { cout << this << "thread id= " << std::this_thread::get_id() << "拷贝构造" << endl; }
~A() { cout << "析构" << this << "thread id= " << std::this_thread::get_id() << endl; }
void thread_work(int num)
{
cout << "thread_work" << endl;
}
};
int main()
{
A myobj(10);
std::thread myThread(&A::thread_work, myobj, 15);//有拷贝构造产生
//std::thread myThread(&A::thread_work, std::ref(myobj), 15);//没有拷贝构造,不能用detach();
if (myThread.joinable()) {
myThread.join();
//myThread.detach();//一定不能是detach
}
return 0;
}
namespace this_thread {
thread::id get_id() noexcept;
inline void yield() noexcept;
void sleep_until(const xtime* _Abs_time) ;
void sleep_for(const chrono::duration<_Rep, _Period>& _Rel_time)
};
作用同 std::thread::get_id(); 获取线程ID值;
void threadFunc3()
{
std::cout << std::this_thread::get_id() << endl;//32320
}
int main()
{
std::thread myThread(threadFunc3);
std::cout << myThread.get_id() << std::endl;//32320
if (myThread.joinable()) {
myThread.join();
}
return 0;
}
yield参考
阻塞当前正在执行的线程直到sleep_time溢出。 参考
延时一段时间,支持ns到hour;
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::nanoseconds(1000));//1000ns
std::this_thread::sleep_for(std::chrono::microseconds(1000));//1000us
std::this_thread::sleep_for(std::chrono::milliseconds(1000));//1000ms
std::this_thread::sleep_for(std::chrono::seconds(5));//5s
std::chrono::duration elapsed = std::chrono::high_resolution_clock::now() - start;
std::cout << elapsed.count() << endl;