C++11 std::thread 实现
- std::thread主要接口
thread() noexcept; // 创建不表示线程的空线程对象 template< class Function, class... Args > explicit thread( Function&& f, Args&&... args ); // 创建新线程并执行函数 thread( const thread& ) = delete; // 不可复制构造 thread( thread&& other ) noexcept; // 移动构造 join() //阻塞当前线程,直到目标线程执行完毕 detach() //分离线程,允许线程独立执行;分离后线程对象不再管理该线程 joinable() //检查线程是否可合并 //返回 true 的情况: //1.通过构造函数创建且未调用 join/detach //2.已移动但未管理的线程对象 get_id() //返回线程的唯一标识符,如果线程不可合并,返回默认构造的 id hardware_concurrency() //返回硬件支持的并发线程数,用于指导线程池大小设置 void swap(thread& _Other) noexcept//交换两个 std::thread 对象的底层句柄-实例
#include <stdio.h> // 标准输入输出头文件 #include <stdlib.h> // 标准库头文件(包含exit等函数) #include <iostream> // C++标准输入输出流 #include <cstring> #include <thread> #include <chrono> using namespace std; // 使用std命名空间 // 线程函数 - 子线程的入口点 void PrintThread(int param) { thread::id thread_id = this_thread::get_id(); cout << "ChildThread:" << " id=" << thread_id<< endl; // 这里打印的是进程ID for (int i = 0; i < 100; i++) { cout << i << endl; this_thread::sleep_for(chrono::seconds(1)); // 休眠1秒,模拟耗时操作 } } //静态函数 static void staticPrintThread(int param){ return PrintThread(param); } int main(int argc, char* argv[]) { thread::id main_id = this_thread::get_id(); // 获取当前进程ID cout << "main Self:" << " id=" << main_id << endl; int temp = 50; // 创建新线程 thread t(PrintThread,temp); //thread t(staticPrintThread,temp); //引用传递 //thread t(PrintThread,ref(temp); // 主线程继续执行自己的工作(与子线程并发执行) for (int i = 0; i < 5; i++) { cout << "Main thread " << i << endl; // 主线程输出 this_thread::sleep_for(chrono::seconds(2)); // 休眠2秒(子线程休眠1秒,所以子线程输出更频繁) } if (t.joinable()) { t.join(); } return 0; }Lambda表达式
int temp = 5; thread t([temp](int count){ for (int i = temp; i < count; i++) { cout << i << endl; this_thread::sleep_for(chrono::seconds(1)); // 休眠1秒,模拟耗时操作 } },30);调用类普通方法、类静态方法
#include <iostream> #include <thread> #include <chrono> #include <functional> using namespace std; class ProgramA{ public: void PrintThread(){ thread::id thread_id = this_thread::get_id(); cout <<"thread_id: "<<thread_id<<endl; for(int i = 0;i<50;i++){ cout<<"fun" << i <<endl; this_thread::sleep_for(chrono::seconds(1)); } return; }; static void staticPrintThread(){ thread::id thread_id = this_thread::get_id(); cout <<"thread_id: "<<thread_id<<endl; for(int i = 0;i<50;i++){ cout<<"static" << i <<endl; this_thread::sleep_for(chrono::seconds(1)); } return ; } }; int main(){ thread t1(ProgramA::staticPrintThread); ProgramA PA; thread t2(&ProgramA::PrintThread,&PA); thread t3(bind(&ProgramA::PrintThread,&PA)); thread t4(&ProgramA::PrintThread,&PA); t1.join(); t2.join(); t3.join(); t4.join(); }promise、future、async
问题:如果有一个使用场景计算A需要5min,计算B需要4分钟,执行C动作需要完成A和B。不使用多线程时需要9min
才能执行C,使用多线程时只需要5min就可以完成前面步骤。
但是如何保证AB完成后才让C执行。
在执行C之前让A、B join();
使用promise、future、async
promise-future 对是通过共享状态,来帮助线程间传递值或异常的一种沟通通道。是实现线程同步的一种方式。
std::promise:数据提供者;用于存储一个值或异常,之后可以通过与之关联的std::future来获取这个值或异常。
std::future:数据接收者;提供一个异步操作结果的访问。它可以等待(阻塞)直到std::promise设置好值,然后获取该值。
std::async:用于异步执行任务,并返回一个std::future对象来获取结果
- promise、future示例
promise
get_future(): 返回一个与该promise关联的future对象。每个 promise 只能调用一次
get_future(),多次调用会抛出std::future_error异常。
set_value(value): 设置异步操作的结果值。如果多次调用会抛出std::future_error异常。
set_exception(exception_ptr): 设置异步操作的异常。
set_value_at_thread_exit(value): 设置异步操作的结果值,但该值会在当前线程退出时才变得可用。
set_exception_at_thread_exit(exception_ptr): 设置异步操作的异常,但该异常会在当前线程退出时才变得可用。
future
get(): 阻塞当前线程,直到异步操作完成并返回结果。
get()只能调用一次,第二次调用会抛出std::future_error异常。
wait(): 阻塞当前线程,直到异步操作完成,但不获取结果。
wait_for(duration): 阻塞当前线程,直到异步操作完成或指定的时间已过。
wait_until(time_point): 阻塞当前线程,直到异步操作完成或到达指定的时间点。
设置返回值
1 #include <iostream> 2 #include <thread> 3 #include <chrono> 4 #include <functional> 5 #include <future> 6 7 using namespace std; 8 void computeA(promise<int> &&prom){ 9 this_thread::sleep_for(chrono::seconds(5));//5s 10 cout<< "A执行完成! 5s" <<endl; 11 prom.set_value(1);//设置结果值 12 } 13 14 15 void computeB(promise<float> &&prom){ 16 this_thread::sleep_for(chrono::seconds(4));//4s 17 cout<< "B执行完成! 4s" <<endl; 18 prom.set_value(1);//设置结果值 19 } 20 21 22 void computeC(future<int> &&futi,future<float> &&futf){ 23 cout<< "C开始!" <<endl; 24 futi.get(); 25 futf.get(); 26 cout<< "C接受A B结果后执行!" <<endl; 27 } 28 29 int main(){ 30 31 promise<int> prom_i; 32 future<int> resultFutI = prom_i.get_future(); 33 34 promise<float> prom_f; 35 future<float> resultFutF= prom_f.get_future(); 36 37 38 thread threadA = thread(computeA , move(prom_i)); 39 40 thread threadB = thread(computeB , move(prom_f)); 41 42 thread threadC = thread(computeC , move(resultFutI) , move(resultFutF)); 43 44 45 threadA.join(); 46 47 threadB.join(); 48 49 threadC.join(); 50 }设置异常
1 #include <iostream> 2 #include <thread> 3 #include <chrono> 4 #include <functional> 5 #include <future> 6 using namespace std; 7 void funAThrowException(std::promise<int>&& prom) { 8 try { 9 throw std::runtime_error("An error occurred"); 10 } catch (...) { 11 prom.set_exception(std::current_exception()); 12 } 13 } 14 15 void funBReceiveException(std::future<int>&& fut) { 16 try { 17 int value = fut.get(); 18 } catch (const std::exception& e) { 19 std::cout << "Caught exception: " << e.what() << std::endl; 20 } 21 } 22 23 24 int main(){ 25 cout<<"main fun! "<<endl; 26 promise<int> prom; 27 future<int> fut = prom.get_future(); 28 thread threadA = thread(funAThrowException,move(prom)); 29 thread threadB = thread(funBReceiveException,move(fut)); 30 threadA.join(); 31 threadB.join(); 32 return 0; 33 34 }