C++多线程基础


前言

提示:VS2019


提示:以下是本篇文章正文内容

一、多线程介绍

自搜

二、测试

1、线程的类外使用

#include<iostream>
#include<thread>
#include<mutex>
#include<Windows.h>
#include <synchapi.h>
#include <vector>
//1、测试线程的使用
void procThread(int* num, int* temp)
{
	*num = *temp;
	std::cout << "I am sub thread! num = " << *num << '\n';
	Sleep(5 * 1000);
}

int main()
{
	//1、线程的类外使用
	int num = 100;
	int temp = 200;
	//1、传入的是100,经测试thread对象在初始化时,使用引用传递会出现错误,使用地址传递可解决问题
	std::thread th(procThread, &num, &temp);
	//1、子线程还没运行完,num已经变成101,但不影响子线程
	//这是因为只要创建了线程对象,那么线程就开始执行
	//之后在主线程被阻塞前,主线程可以做自己的事
	std::cout << "子线程join之前 num = " << ++num << '\n';
	//join(), 当前线程(这里是主线程)暂停, 等待指定的线程执行结束后, 当前线程再继续。
	//即,主线程被阻塞,一般在使用时表现为需要等待子线程的结果,才能进行之后的操作
	th.join();
	std::cout << "子线程join之后 num = " << num << '\n';

	return 0;
}

2、线程的类内使用

将在这里介绍C++线程中互斥量的使用
#include<mutex>

2.1、lock()与unlock()

直接使用mutex加解锁。
我的理解是:mutex使自己互斥,那么自身在被一个线程锁定时,其他线程将不能锁定它(即与已使用的线程产生互斥)。
作用:互斥量在加锁和解锁之间,可保护数据,不被几个线程同时使用,出现内存错误。
procMutex0与procMutex1运行分析:

  1. procMutex0与procMutex1并行
  2. 互斥量加锁,锁的是自己
  3. procMutex0与procMutex1两个函数共用同一个互斥锁,才能实现数据IO的原子性(安全)
  4. 不共用互斥将没有意义:先不对A、B只有一方上锁的情况进行分析

2.2、lock_guard

adopt_lock:不在构造函数中自动加锁,但在析构函数中自动解锁
procMutex3与procMutex4运行分析:

  1. procMutex3:使用加锁后的互斥量对象和adopt_lock初始化自身,表示在出自身定义域后(析构时),自动解锁。
  2. procMutex4:使用未加锁的互斥量对象初始化自身,表示在自身初始化时加锁(构造),出自身定义域后(析构时),自动解锁。

2.3、unique_lock

adopt_lock:在构造时不加锁,析构自动解锁
try_to_lock:尝试去锁定,得保证锁处于unlock的状态,然后尝试现在能不能获得锁;尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
defer_lock:初始化一个没有加锁的mutex
procMutex2与procMutex5运行分析:

  1. procMutex2:使用未加锁(unlock)的互斥量和try_to_lock初始化自身,尝试去锁定,失败,会不阻塞,直接返回。
  2. procMutex5:使用未加锁(unlock)的互斥量和defer_lock初始化自身,可对互斥量临时解锁。

3、测试代码

#include<iostream>
#include<thread>
#include<mutex>
#include<Windows.h>
#include <synchapi.h>
#include <vector>
//1、测试线程的使用
void procThread(int* num, int* temp) 
{
	*num = *temp;
	std::cout << "I am sub thread! num = " << *num << '\n';
	Sleep(5 * 1000);
}



//2、测试锁mutex的使用
class TestMutex{
private:
	std::mutex m;
	int num = 100;
	std::vector<std::thread> tmVector;

	void procMutex0(int* num)
	{
		//2.1、直接使用mutex加解锁
		m.lock();
		std::cout << "procMutex0正在操作num,num = " << ++*num << '\n';
		Sleep(5 * 1000);
		m.unlock();
	}

	void procMutex1(int*  num)
	{
		m.lock();
		*num += 100;
		std::cout << "procMutex1正在操作num,num = " << *num << '\n';
		Sleep(5 * 1000);
		m.unlock();
	}

	void procMutex2(int* num)
	{
		std::cout << "proMutex2 能得到锁吗?\n";
		std::unique_lock<std::mutex> ul(m, std::try_to_lock);
		std::cout << "proMutex2 得到锁了!\n";
		*num += 100000;
		std::cout << "procMutex2正在操作num,num = " << *num << '\n';
	}//自动解锁

	void procMutex3(int* num)
	{
		//2.2.1、测试lock_guard(锁警卫),在自身定义域内加解数据,出了定义域之后自动解锁
		//不在构造函数中自动加锁,但在析构函数中自动解锁
		m.lock();
		std::lock_guard<std::mutex> lg1(m, std::adopt_lock);
		*num += 1000;
		std::cout << "procMutex3正在操作num,num = " << *num << '\n';
		Sleep(5 * 1000);
	}//自动解锁

	void procMutex4(int* num) 
	{
		//2.2.2、在构造函数中自动加锁,在析构函数中自动解锁
		{
			std::lock_guard<std::mutex> lg2(m);
			*num += 10000;
			std::cout << "procMutex4正在操作num,num = " << *num << '\n';
		}//自动解锁
		Sleep(5 * 1000);
		std::cout << "proMutex4 must do something else\n";

	}

	void procMutex5(int* num) 
	{
		//2.3.1、unique_lock(唯一锁),具备lock_guard的功能,但含义更加丰富
		// adopt_lock:在构造时不加锁,析构自动解锁
		// try_to_lock:尝试去锁定,得保证锁处于unlock的状态,然后尝试现在能不能获得锁;尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
		// defer_lock:初始化一个没有加锁的mutex
		//初始化一个没有加锁的mutex对象,
		{
			std::unique_lock<std::mutex> ul(m, std::defer_lock);
			std::cout << "procMutex5 要开始操作了 num == " << *num << '\n';
			ul.lock();
			std::cout << "procMutex5 上锁成功\n";
			*num += 1;
			ul.unlock();//可临时解锁
			int a = 10;
			ul.lock();
			*num += a;
		}//自动解锁
		std::cout << "procMutex5 操作结束 num == " << *num << '\n';

	}

public:
	//thread类内使用
	/*运行分析
	* procMutex0与procMutex1并行
	* 互斥锁锁的是自己
	* A、B两个函数共用同一个互斥锁,才能实现数据IO的原子性(安全)
	* 不共用互斥将没有意义:先不对A、B只有一方上锁的情况进行分析
	*/
	void testMutex(int threadSize)
	{
		this->tmVector.push_back(std::thread(&TestMutex::procMutex0, this, &(this->num)));
		this->tmVector.push_back(std::thread(&TestMutex::procMutex1, this, &(this->num)));
		this->tmVector.push_back(std::thread(&TestMutex::procMutex2, this, &(this->num)));
		tmVector.push_back(std::thread(&TestMutex::procMutex3, this, &num));
		tmVector.push_back(std::thread(&TestMutex::procMutex4, this, &num));
		tmVector.push_back(std::thread(&TestMutex::procMutex5, this, &num));

		int thlength = tmVector.size();
		for (int i = 0; i < thlength; ++i) 
		{
			tmVector[i].join();
		}
		std::cout << "testMutex num = " << num << '\n';

	}

};

int main() 
{
	//1、
	int num = 100;
	int temp = 200;
	//1、传入的是100,经测试thread对象在初始化时,使用引用传递会出现错误,使用地址传递可解决问题
	std::thread th(procThread, &num, &temp);
	//1、子线程还没运行完,num已经变成101
	std::cout << "子线程join之前 num = " << num << '\n';
	th.join();
	std::cout <<"子线程join之后 num = " << num << '\n';

	//2、
	TestMutex tm;
	tm.testMutex(2);

	return 0;
}

总结

提示:未完待续。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值