ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C++11并发支持库

C++11并发支持库 bit::Shadow✧(≖ ◡ ≖✿目录1.线程库2.std::chrono时间控制类3.多种多样的锁std::this_thread::*使用lambda表达式处理线程调用函数☆*禁拷贝的锁传参——ref()atomic内存序condition_variableasync与futureasync异步与线程的区别get VS waitpromiseshared_futurepackage_task本篇的写作背景是为了“认识 了解”相应接口及性质不是为了实践级复习。写给读者若追求详细、实践 请离开此文章。1.thread线程库2.std::chrono时间控制类3.多种多样的锁lock_guardunique_lockrecursive_mutex // 递归互斥锁try_lock // 尝试锁try_to_lockstd::this_thread::线程ID获取与线程定时休眠*使用lambda表达式处理线程调用函数☆*禁拷贝的锁传参——ref()注意x也必须是ref。---编译错误atomic整型与指针常用于#include iostream #include atomic #include thread #include vector std::atomicint counter(0); // 原子整型初始值为 0 void worker() { for (int i 0; i 100000; i) { // 原子自增等价于 counter.fetch_add(1) counter; } } int main() { std::vectorstd::thread threads; // 启动 10 个线程 for (int i 0; i 10; i) { threads.emplace_back(worker); } // 等待所有线程结束 for (auto t : threads) { t.join(); } // 期望结果10 * 100000 1000000 std::cout counter counter.load() std::endl; return 0; }原理load意为读取原子变量中的值同时也有std::atomic::compare_exchange_strong()使用较少内存序在大量数据下如果有必要的话我们可以手动定制内存序以提升效率condition_variable条件变量 std::condition_variablestd::condition_variable::wait()std::condition_variable::notify_one()std::condition_variable::notify_all()注意条件变量使用unique_lock限定。无互斥锁#include iostream #include queue #include mutex #include condition_variable #include thread #include chrono std::queueint q; // 共享队列 std::mutex mtx; // 保护队列的互斥锁 std::condition_variable cv; // 条件变量 bool finished false; // 生产者结束标志 // 生产者线程 void producer() { for (int i 1; i 5; i) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产耗时 { std::lock_guardstd::mutex lock(mtx); q.push(i); std::cout 生产者生产: i std::endl; } // 离开作用域自动解锁 cv.notify_one(); // 通知一个等待的消费者 } // 生产结束设置标志并唤醒消费者 { std::lock_guardstd::mutex lock(mtx); finished true; } cv.notify_one(); } // 消费者线程 void consumer() { while (true) { std::unique_lockstd::mutex lock(mtx); // 等待条件成立队列非空 或 生产结束 // 使用 lambda 防止虚假唤醒spurious wakeup cv.wait(lock, [] { return !q.empty() || finished; }); // 如果队列空了且生产结束退出循环 if (q.empty() finished) { break; } // 取出数据 int value q.front(); q.pop(); std::cout 消费者消费: value std::endl; lock.unlock(); // 处理完数据后可以提前解锁可选 } std::cout 消费者结束 std::endl; } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; }async与future异步执行与延迟执行asyncauto的类型是std::futurevoid task(const char* name) { std::cout name 开始执行, 线程ID: std::this_thread::get_id() std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout name 完成 std::endl; } int main() { std::cout 主线程ID: std::this_thread::get_id() std::endl; // 异步执行新线程 auto f1 std::async(std::launch::async, task, 异步任务); // 延迟执行调用get时执行 auto f2 std::async(std::launch::deferred, task, 延迟任务); std::cout 主线程工作... std::endl; f1.get(); // 等待异步任务完成 f2.get(); // 此时才执行延迟任务 return 0; }async异步与线程的区别“async”是线程的轻量化管理体系。std::thread给你一个裸线程你自己管一切std::async给你一个任务库帮你管执行和结果。我们使用时从其便捷的接口就可以得出futurestd::future是 C11 引入的用于访问异步操作结果的类模板。它代表一个未来会得到的结果你可以通过它获取另一个线程或延迟任务计算出的值。核心成员函数get() wait() wait_for()/wait_until()get VS wait对比项wait()get()返回值无void任务的返回值是否取走结果❌ 不取结果仍留在 future 里✅ 取走future 变为无效状态能否重复调用✅ 可以多次❌只能调用一次异常处理不抛出任务里的异常会重新抛出任务里的异常对共享状态的影响保持不变使 future 失效valid() falsepromise内部封装了future主要用于get()、wait() 取结果。set_value( )与set_value_at_thread_exit()在不同时机设置get()的结果值。set_value() 直接唤醒get若有 set_value_at_thread_exit()不会立即唤醒get()若有只有在任务结束后才会。注意二者均线程不安全shared_future实现了让多个线程或从多个地方能够安全地读取同一个异步结果。get() . . .package_task封装了promise、future的结合体**用例线程池代码class ThreadPool { public: // 构造函数启动指定数量的工作线程 ThreadPool(size_t threads) : stop(false) { for (size_t i 0; i threads; i) { workers.emplace_back([this] { for (;;) { std::functionvoid() task; { std::unique_lockstd::mutex lock(this-queue_mutex); // 队列为空始终wait阻塞 this-condition.wait(lock, [this] { return this-stop || !this-tasks.empty(); }); // 线程池退出 if (this-stop this-tasks.empty()) return; task std::move(this-tasks.front()); this-tasks.pop(); } task(); } }); } } // 向线程池添加任务 templateclass F, class... Args auto enqueue(F f, Args... args) - std::futuretypename std::result_ofF(Args...)::type { using return_type typename std::result_ofF(Args...)::type; //std::packaged_task return_type()* ptask new std::packaged_task return_type()() auto task std::make_sharedstd::packaged_taskreturn_type()( std::bind(std::forwardF(f), std::forwardArgs(args)...) ); std::futurereturn_type res task-get_future(); { std::unique_lockstd::mutex lock(queue_mutex); // 不允许在停止线程池后添加新任务 if (stop) throw std::runtime_error(enqueue on stopped ThreadPool); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } // 析构函数等待所有任务完成 ~ThreadPool() { { std::unique_lockstd::mutex lock(queue_mutex); stop true; } condition.notify_all(); for (std::thread worker : workers) worker.join(); } private: // 工作线程集合 std::vectorstd::thread workers; // 任务队列 std::queuestd::functionvoid() tasks; // 同步原语 std::mutex queue_mutex; std::condition_variable condition; bool stop; };本篇完
返回列表