线程睡眠很稳定,但无线程睡眠不稳定
线程调用类方法:
有参数时调用方法:
当参数为引用时:
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文章来源:https://www.toymoban.com/news/detail-703784.html
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暂时没找到打印的办法,但是能够编过断点也有对应效果文章来源地址https://www.toymoban.com/news/detail-703784.html
到了这里,关于C++ 多线程 学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!