前言
提示: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运行分析:
- procMutex0与procMutex1并行
- 互斥量加锁,锁的是自己
- procMutex0与procMutex1两个函数共用同一个互斥锁,才能实现数据IO的原子性(安全)
- 不共用互斥将没有意义:先不对A、B只有一方上锁的情况进行分析
2.2、lock_guard
adopt_lock:不在构造函数中自动加锁,但在析构函数中自动解锁
procMutex3与procMutex4运行分析:
- procMutex3:使用加锁后的互斥量对象和adopt_lock初始化自身,表示在出自身定义域后(析构时),自动解锁。
- procMutex4:使用未加锁的互斥量对象初始化自身,表示在自身初始化时加锁(构造),出自身定义域后(析构时),自动解锁。
2.3、unique_lock
adopt_lock:在构造时不加锁,析构自动解锁
try_to_lock:尝试去锁定,得保证锁处于unlock的状态,然后尝试现在能不能获得锁;尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
defer_lock:初始化一个没有加锁的mutex
procMutex2与procMutex5运行分析:
- procMutex2:使用未加锁(unlock)的互斥量和try_to_lock初始化自身,尝试去锁定,失败,会不阻塞,直接返回。
- 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;
}
总结
提示:未完待续。