线程管理
1. 启动线程
启动一个简单的线程
范例 1
使用普通函数
#include <thread>
#include <iostream>
void do_task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
int main()
{
//创建一个线程
std::thread t = std::thread(do_task);
//堵塞主线程,等待子线程执行完毕
t.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
范例 2
使用lambda
#include <thread>
#include <iostream>
int main()
{
for (int i = 0; i < 20; ++i) {
std::thread t = std::thread([i](){
std::cout << "thread " << i << " id:" << std::this_thread::get_id() << std::endl;
});
t.join();
}
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
范例 3
仿函数(重载运算符)
#include <thread>
#include <iostream>
class Task
{
public:
//重载()操作符
void operator()(int i)
{
std::cout << "task thread " << i << "id:" << std::this_thread::get_id() << std::endl;
}
};
int main()
{
Task task;
//创建线程,并且传递参数
std::thread t = std::thread(task, 10);
//堵塞主线程,等待子线程完成
t.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
2.向线程传递参数
默认的方式是使用拷贝的方式,复制到线程空间,即使参数的类型是引用
使用指针传递参数
#include <thread>
#include <stdio.h>
void task(const char* pBuffer, int n)
{
fprintf(stdout, "buffer: %s, %d", pBuffer, n);
}
int main()
{
char* buffer = NULL;
int n = 10;
//申请12字节的内存
buffer = (char*)malloc(sizeof(char) * 12);
//拷贝到数据到buffer
strcpy(buffer, "hello thread");
//传递的参数, 不能是右值的零时变量
std::thread t = std::thread(task, buffer, n);
t.join();
return 0;
}
使用std::ref
#include <thread>
#include <iostream>
#include <string>
class ObjectClass
{
public:
ObjectClass(std::string& data)
:m_data(data)
{}
public:
std::string& m_data;
};
void func(ObjectClass& object)
{
std::cout << "objectName:" << object.m_data << std::endl;
}
int main()
{
std::string tag = "object";
ObjectClass object(tag);
//创建线程, 使用std::ref传递引用的对象
std::thread t = std::thread(func, std::ref(object));
//堵塞线程,等待子线程执行完毕
t.join();
return 0;
}
使用类中的方法
#include <thread>
#include <iostream>
#include <string>
class ObjectClass
{
public:
explicit ObjectClass(std::string& tag)
:m_tag(tag)
{}
void func(int n)
{
std::cout << "tag:" << this->m_tag << ", n:" << n << std::endl;
}
private:
std::string& m_tag;
};
int main()
{
std::string tag = "object";
ObjectClass object(tag);
//使用类方法,放到子线程中使用;
std::thread t = std::thread(&ObjectClass::func, &object, 10);
//堵塞线程,等待子线程执行完毕
t.join();
return 0;
}
3.线程权限转移
thread 是可移动(movable), 但是不可复制的(copyable)
#include <thread>
#include <iostream>
void do_task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
int main()
{
//创建一个线程
std::thread t = std::thread(do_task);
//线程t的权限移动到t2后,t变得不确定,
std::thread t2 = std::thread(std::move(t));
t2.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
4.异常的线程处理
局部变量
局部变量引用的误区
#include <thread>
#include <iostream>
void task(int* pInt)
{
std::cout << "int value:" << *pInt << std::endl;
}
int main()
{
int i = 10;
//创建线程
std::thread t = std::thread(task, &i);
//分离子线程
t.detach();
//主线程执行完毕,i变量资源回收,i的值变的不确定
return 0;
}
主线程异常
当主线程发生异常时,如何保证子线程正确被回收
范例1
子线程不分离
#include <thread>
#include <iostream>
#include <exception>
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void do_something()
{
throw std::runtime_error("has exception");
}
int main()
{
std::thread t(task);
try {
//主线程在执行过程中,发生异常,为了正确处理,线程等待,需要加入异常处理
do_something();
} catch (std::exception & e)
{
//等待子线程完成
t.join();
throw e;
}
//等待子线程完成
t.join();
return 0;
}
范例 2
子线程分离
#include <thread>
#include <iostream>
#include <exception>
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void do_something()
{
throw std::runtime_error("has exception");
}
int main()
{
//创建线程
std::thread t = std::thread(task);
//线程分离,为了防止在创建线程后发生异常,导致线程无法回收
t.detach();
do_something();
return 0;
}
范例 3
使用资源管理类
#include <thread>
#include <iostream>
#include <exception>
class ThreadGuard
{
public:
//构造函数
explicit ThreadGuard(std::thread&t)
:t(t){}
//析构函数
~ThreadGuard()
{
//析构函数时,顺道堵塞主线程,等待子线程执行完毕,这就是资源回收
if(t.joinable())
{
t.join();
}
}
private:
std::thread &t;
};
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void func()
{
std::thread t = std::thread(task);
ThreadGuard guard(t);
//超出作用域后,自动回收资源
}
void do_task()
{
throw std::runtime_error("exception");
}
int main()
{
func();
do_task();
return 0;
}