C++ 多线程 学习笔记

线程睡眠很稳定,但无线程睡眠不稳定


线程调用类方法:


有参数时调用方法:


当参数为引用时:


detach分离线程,分离线程与主线程同时进行,join会使主线程挂起,执行join进来的进程

detach必须让主线程在还住运行的情况下调用,换句话说就是不能让detach的线程还没结束,主线程就结束,同时detach的函数传参不能是局部变量,换句话来说就是不能调用的函数还没结束,该变量就被销毁了


当同一资源被多个线程同时引用时,为防止资源抢占,使用mutex,互斥锁

头文件#include "mutex"


lock_guard<类型> 变量名(锁变量);

作用,为防止死锁发生,它可以进行锁的自动加锁和解锁


unique_lock<类型> 变量名(锁名, 变参参数);

延时加锁,直接这样定义数据会出现混乱

必须手动锁定 

直接用变参std::adopt_lock也会直接造成数据混乱 

std::adopt_lock只是用于接管之前的锁mtx,所以在这一行之前需要对mtx进行lock才会真正的被lock


#include <condition_variable>

用于主线程,子线程按次序执行

如果需要线程一个一个执行,则可以这样写

#include "iostream"
#include "chrono"
#include "thread"
#include "condition_variable"
#include "mutex"

using namespace std;

mutex mtx;
condition_variable cv;
bool sub_run = false;
int number = 0;

class A {
public:
	void add(int &b) {
		while (b < 10) {
			unique_lock<mutex> queLock(mtx);
			cv.wait(queLock, [&] { return !(number - 1); });
			b++; 
			cout << " add " << b << endl;
			this_thread::sleep_for(chrono::milliseconds(10));
			number = 2;
			cv.notify_all();
		}
	}
};

void Dec(int& c) {
	while (c < 10) {
		unique_lock<mutex> uniLock(mtx);
		cv.wait(uniLock, [&] { return !number; });
		c--;
		cout << " Dec " << c << endl;
		this_thread::sleep_for(chrono::milliseconds(10));
		number = 1;
		cv.notify_all();
	}
}

int main() {
	A a;
	int num = 5;
	thread th(&A::add, &a, ref(num));
	thread th1(Dec, ref(num));
	while (num < 10) {
		unique_lock<mutex> mainUniLock(mtx);
		cv.wait(mainUniLock, [&] { return !(number - 2); });
		num++;
		cout << " Main " << num << endl;
		this_thread::sleep_for(chrono::milliseconds(10));
		number = 0;
		cv.notify_all();
	}
	th.join();
	th1.join();
	cout << num << endl;

	return 0;
}


nofity_one()只会随机唤醒其中运行的一个线程


call_once(once_flag, this_thread::get_id());

头文件:  #include "mutex"

作用:线程只能调用该方法一次

只调用了一次

主线程没有限制 


如何在join前就获取最终num的结果?

promise     future

头文件:#include "future"


自定义启动线程函数:

头文件#include "future"

packaged_task<函数类型> 变量名(函数名);

主要是能与promise、future搭配使用


async

头文件#include "future"

fvalue.get()过后才会进行函数调用


原子操作

允许无所并发编程,涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的,原子对象不具有数据竞争

头文件:#include "atomic"

锁是在牺牲性能的情况下进行对操作的细致管控,这个时候就用原子变量

不加锁:

加锁:

原子操作:


C++11 多线程std:: async与std::thread的区别_c++11 thread asy-CSDN博客

参考:60 工具库-tuple_哔哩哔哩_bilibili


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	int a = 1;
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	th.join();
	
}

// Called every frame
void ATaskTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		//std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		mtx.unlock();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	th.detach();
}

// Called every frame
void ATaskTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		mtx.unlock();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
	th.detach();
	th1.detach();
}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

会一增一减


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
	th.detach();
	th1.detach();
}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		std::unique_lock<std::mutex> uniLock(mtx, std::defer_lock);
		uniLock.lock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

unique_lock与lock_guard一样,在函数结束后会自动解锁,但unique_lock有更多操作,比如延迟加锁,接管锁,wait锁(wait不接受lock_guard)如果不需要这些操作还是lock_guard好一点,越多操作性能消耗也越高


std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


std::mutex mtx;
std::condition_variable cv;
bool isFirst = false;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
		cv.wait(uniLock, [=] {return !isFirst; });
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		isFirst = true;
		cv.notify_all();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::unique_lock<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		cv.wait(guardLock, [=] {return isFirst; });
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
		isFirst = false;
		cv.notify_all();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

while内一个执行一次,使用std::condition_variable


std::atomic_int a(1);
void ATaskTest::ThreadDo() {
    while (a < 10000) {
        a++;
        //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    }
}

void ATaskTest::ThreadDo1() {
    while (a < 10000) {
        a--;
        //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    }
}

atomic_int暂时没找到打印的办法,但是能够编过断点也有对应效果

猜你喜欢

转载自blog.csdn.net/qqQQqsadfj/article/details/132781804