ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c++多线程

2022-05-10 21:03:40  阅读:172  来源: 互联网

标签:std lock 张票 c++ 线程 ticket 多线程 无票


参考链接: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));
	}
}

picLoadErr

标签:std,lock,张票,c++,线程,ticket,多线程,无票
来源: https://www.cnblogs.com/shegb1997/p/16255295.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有