c++多线程
2022/5/10 22:00:24
本文主要是介绍c++多线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
参考链接:https://www.cnblogs.com/zizbee/p/13520823.html
c++创建线程的方式
需要包含头文件#include <thread>
// 准备用于创建线程的函数 void proc(int a) { std::cout << "我是子线程" << std::this_thread::get_id() << ",传入参数为" << a << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "子线程" << std::this_thread::get_id() << "结束" << std::endl; } int main(){ std::cout << "我是主线程" << std::endl; thread th(proc,9); // 创建线程 th.join(); // 主线程阻塞的,等待th线程执行结束主线程再继续 std::cout << "主线程" << std::this_thread::get_id() << "结束" << std::endl; return 0; } // 注意:只要创建了线程对象(传递“函数名/可调用对象”作为参数的情况下),线程就开始执行(std::thread 有一个无参构造函数重载的版本,不会创建底层的线程)。
多线程经典案例:买票
同时开启多个线程进行购票,如果不加锁就会出现以下情况:
代码:
#include <thread> #include <iostream> #include <vector> int ticket_num_left = 10; // 一共10张票 void buy_ticket(int id) { while (true) { if (ticket_num_left > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(30)); ticket_num_left--; std::cout << "线程" << id << "买了一张票,现在还剩" << ticket_num_left << "张票" << std::endl; } else { std::cout << "线程" << id << "无票可买" << std::endl; break; } std::this_thread::sleep_for(std::chrono::milliseconds(30)); } } int main() { std::cout << "我是主线程" << std::endl; std::vector<std::thread*> threads; // 同时开启9个线程一起买票 for (int i = 0; i < 9; i++) { std::thread* th_ptr = new std::thread(buy_ticket, i + 1); threads.push_back(th_ptr); } for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) { (*it)->join(); } std::cout << "主线程" << std::this_thread::get_id() << "结束" << std::endl; return 0; }
运行结果如下,出现奇怪的票数:
我是主线程 线程5买了一张票,现在还剩2张票 线程2买了一张票,现在还剩2张票 线程9买了一张票,现在还剩2张票 线程8买了一张票,现在还剩2张票 线程1买了一张票,现在还剩2张票 线程3买了一张票,现在还剩2张票 线程7买了一张票,现在还剩2张票 线程6买了一张票,现在还剩2张票 线程4买了一张票,现在还剩2张票 线程2买了一张票,现在还剩-1张票 线程9买了一张票,现在还剩-1张票 线程5买了一张票,现在还剩-1张票 线程7买了一张票,现在还剩-7张票 线程1买了一张票,现在还剩-7张票 线程4买了一张票,现在还剩-7张票 线程3买了一张票,现在还剩-7张票 线程8买了一张票,现在还剩-7张票 线程6买了一张票,现在还剩-7张票 线程2无票可买 线程5无票可买 线程9无票可买 线程3无票可买 线程6无票可买 线程8无票可买 线程7无票可买 线程1无票可买 线程4无票可买 主线程23060结束
原因分析:
解决方法:单个线程在购票时,使用互斥量加锁
#include <mutex>
方法一:lock()与unlock()
代码:
#include <thread> #include <iostream> #include <vector> #include <mutex> int ticket_num_left = 10; std::mutex mutex_; void buy_ticket(int id) { while (true) { mutex_.lock(); if (ticket_num_left > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(30)); ticket_num_left--; std::cout << "线程" << id << "买了一张票,现在还剩" << ticket_num_left << "张票" << std::endl; } else { std::cout << "线程" << id << "无票可买" << std::endl; mutex_.unlock(); break; } mutex_.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(30)); } } int main() { std::cout << "我是主线程" << std::endl; std::vector<std::thread*> threads; for (int i = 0; i < 9; i++) { std::thread* th_ptr = new std::thread(buy_ticket, i + 1); threads.push_back(th_ptr); } for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) { (*it)->join(); } std::cout << "主线程" << std::this_thread::get_id() << "结束" << std::endl; return 0; }
运行结果:
我是主线程 线程2买了一张票,现在还剩9张票 线程1买了一张票,现在还剩8张票 线程3买了一张票,现在还剩7张票 线程4买了一张票,现在还剩6张票 线程5买了一张票,现在还剩5张票 线程6买了一张票,现在还剩4张票 线程7买了一张票,现在还剩3张票 线程8买了一张票,现在还剩2张票 线程9买了一张票,现在还剩1张票 线程2买了一张票,现在还剩0张票 线程1无票可买 线程3无票可买 线程4无票可买 线程5无票可买 线程6无票可买 线程7无票可买 线程8无票可买 线程9无票可买 线程2无票可买 主线程17224结束
方法二:lock_guard()
创建即加锁,作用域结束自动解锁。
代码:
#include <thread> #include <iostream> #include <vector> #include <mutex> int ticket_num_left = 10; std::mutex mutex_; void buy_ticket(int id) { while (true) { std::lock_guard<std::mutex> lockGuard(mutex_); // 用lock_guard替代lock和unlock //mutex_.lock(); if (ticket_num_left > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(30)); ticket_num_left--; std::cout << "线程" << id << "买了一张票,现在还剩" << ticket_num_left << "张票" << std::endl; } else { std::cout << "线程" << id << "无票可买" << std::endl; //mutex_.unlock(); break; } //mutex_.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(30)); } } int main() { std::cout << "我是主线程" << std::endl; std::vector<std::thread*> threads; for (int i = 0; i < 9; i++) { std::thread* th_ptr = new std::thread(buy_ticket, i + 1); threads.push_back(th_ptr); } for (std::vector<std::thread*>::iterator it = threads.begin(); it != threads.end(); it++) { (*it)->join(); } std::cout << "主线程" << std::this_thread::get_id() << "结束" << std::endl; return 0; }
方法三:unique_lock
unique_lock类似于lock_guard,只是unique_lock用法更加丰富,同时支持lock_guard()的原有功能。
使用lock_guard后不能手动lock()与手动unlock();使用unique_lock后可以手动lock()与手动unlock();
unique_lock的第二个参数,除了可以是adopt_lock,还可以是try_to_lock与defer_lock;
try_to_lock: 尝试去锁定,得保证锁处于unlock的状态,然后尝试现在能不能获得锁;尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
defer_lock: 始化了一个没有加锁的mutex;
lock_guard | unique_lock | |
---|---|---|
手动lock与手动unlock | 不支持 | 支持 |
参数 | 支持adopt_lock | 支持adopt_lock/try_to_lock/defer_lock |
详见链接:https://www.cnblogs.com/zizbee/p/13520823.html
void buy_ticket(int id) { while (true) { std::unique_lock<std::mutex> deferLock(mutex_, std::defer_lock);//始化了一个没有加锁的mutex //std::lock_guard<std::mutex> lockGuard(mutex_); //mutex_.lock(); deferLock.lock(); if (ticket_num_left > 0) { std::this_thread::sleep_for(std::chrono::milliseconds(30)); ticket_num_left--; std::cout << "线程" << id << "买了一张票,现在还剩" << ticket_num_left << "张票" << std::endl; } else { std::cout << "线程" << id << "无票可买" << std::endl; //mutex_.unlock(); deferLock.unlock(); break; } //mutex_.unlock(); deferLock.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(30)); } }
这篇关于c++多线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26小白家庭 nas 搭建方案-icode9专业技术文章分享
- 2024-06-23AI大模型企业应用实战(14)-langchain的Embedding
- 2024-06-23AI大模型企业应用实战(15)-langchain核心组件
- 2024-06-23AI大模型企业应用实战(16)-langchain核心组件
- 2024-06-23AI 大模型企业应用实战(06)-初识LangChain
- 2024-06-19EntBot.ai: AI Website Chatbot for Product Guides and Development Doc
- 2024-06-17zero-shot-learning-definition-examples-comparison
- 2024-06-06Package Easy(基于 NSIS 的打包exe安装包工具)使用方法-icode9专业技术文章分享
- 2024-06-06基于 casdoor 的 ELK 开源登录认证解决方案: elk-auth-casdoor-icode9专业技术文章分享
- 2024-05-29Elasticsearch慢查询日志配置