参考链接:https://www.cnblogs.com/zizbee/p/13520823.html
需要包含头文件#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)); } }