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));
}
}
标签:std,lock,张票,c++,线程,ticket,多线程,无票 来源: https://www.cnblogs.com/shegb1997/p/16255295.html