• 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

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

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

    1. #include "iostream"
    2. #include "chrono"
    3. #include "thread"
    4. #include "condition_variable"
    5. #include "mutex"
    6. using namespace std;
    7. mutex mtx;
    8. condition_variable cv;
    9. bool sub_run = false;
    10. int number = 0;
    11. class A {
    12. public:
    13. void add(int &b) {
    14. while (b < 10) {
    15. unique_lock<mutex> queLock(mtx);
    16. cv.wait(queLock, [&] { return !(number - 1); });
    17. b++;
    18. cout << " add " << b << endl;
    19. this_thread::sleep_for(chrono::milliseconds(10));
    20. number = 2;
    21. cv.notify_all();
    22. }
    23. }
    24. };
    25. void Dec(int& c) {
    26. while (c < 10) {
    27. unique_lock<mutex> uniLock(mtx);
    28. cv.wait(uniLock, [&] { return !number; });
    29. c--;
    30. cout << " Dec " << c << endl;
    31. this_thread::sleep_for(chrono::milliseconds(10));
    32. number = 1;
    33. cv.notify_all();
    34. }
    35. }
    36. int main() {
    37. A a;
    38. int num = 5;
    39. thread th(&A::add, &a, ref(num));
    40. thread th1(Dec, ref(num));
    41. while (num < 10) {
    42. unique_lock<mutex> mainUniLock(mtx);
    43. cv.wait(mainUniLock, [&] { return !(number - 2); });
    44. num++;
    45. cout << " Main " << num << endl;
    46. this_thread::sleep_for(chrono::milliseconds(10));
    47. number = 0;
    48. cv.notify_all();
    49. }
    50. th.join();
    51. th1.join();
    52. cout << num << endl;
    53. return 0;
    54. }


    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


    1. // Fill out your copyright notice in the Description page of Project Settings.
    2. #include "TaskTest.h"
    3. #include "chrono"
    4. #include "Kismet/KismetSystemLibrary.h"
    5. #include "mutex"
    6. #include "thread"
    7. // Sets default values
    8. ATaskTest::ATaskTest()
    9. {
    10. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
    11. PrimaryActorTick.bCanEverTick = true;
    12. }
    13. // Called when the game starts or when spawned
    14. void ATaskTest::BeginPlay()
    15. {
    16. Super::BeginPlay();
    17. int a = 1;
    18. std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
    19. th.join();
    20. }
    21. // Called every frame
    22. void ATaskTest::Tick(float DeltaTime)
    23. {
    24. Super::Tick(DeltaTime);
    25. }
    26. std::mutex mtx;
    27. void ATaskTest::ThreadDo(int& value) {
    28. while (value < 10000) {
    29. mtx.lock();
    30. //std::this_thread::sleep_for(std::chrono::milliseconds(10));
    31. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    32. value++;
    33. mtx.unlock();
    34. }
    35. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    36. }


    1. // Fill out your copyright notice in the Description page of Project Settings.
    2. #include "TaskTest.h"
    3. #include "chrono"
    4. #include "Kismet/KismetSystemLibrary.h"
    5. #include "mutex"
    6. #include "thread"
    7. // Sets default values
    8. ATaskTest::ATaskTest()
    9. {
    10. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
    11. PrimaryActorTick.bCanEverTick = true;
    12. }
    13. // Called when the game starts or when spawned
    14. void ATaskTest::BeginPlay()
    15. {
    16. Super::BeginPlay();
    17. std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
    18. th.detach();
    19. }
    20. // Called every frame
    21. void ATaskTest::Tick(float DeltaTime)
    22. {
    23. Super::Tick(DeltaTime);
    24. }
    25. std::mutex mtx;
    26. void ATaskTest::ThreadDo(int& value) {
    27. while (value < 10000) {
    28. mtx.lock();
    29. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    30. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    31. value++;
    32. mtx.unlock();
    33. }
    34. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    35. }


    1. // Fill out your copyright notice in the Description page of Project Settings.
    2. #include "TaskTest.h"
    3. #include "chrono"
    4. #include "Kismet/KismetSystemLibrary.h"
    5. #include "mutex"
    6. #include "thread"
    7. // Sets default values
    8. ATaskTest::ATaskTest()
    9. {
    10. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
    11. PrimaryActorTick.bCanEverTick = true;
    12. }
    13. void ATaskTest::BeginPlay()
    14. {
    15. Super::BeginPlay();
    16. std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
    17. std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
    18. th.detach();
    19. th1.detach();
    20. }
    21. std::mutex mtx;
    22. void ATaskTest::ThreadDo(int& value) {
    23. while (value < 10000) {
    24. std::lock_guard guardLock(mtx);
    25. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    26. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    27. value++;
    28. }
    29. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    30. }
    31. void ATaskTest::ThreadDo1(int& value) {
    32. while (value < 10000) {
    33. std::lock_guard guardLock(mtx);
    34. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    35. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    36. value--;
    37. }
    38. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    39. }

    会一增一减


    1. // Fill out your copyright notice in the Description page of Project Settings.
    2. #include "TaskTest.h"
    3. #include "chrono"
    4. #include "Kismet/KismetSystemLibrary.h"
    5. #include "mutex"
    6. #include "thread"
    7. // Sets default values
    8. ATaskTest::ATaskTest()
    9. {
    10. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
    11. PrimaryActorTick.bCanEverTick = true;
    12. }
    13. void ATaskTest::BeginPlay()
    14. {
    15. Super::BeginPlay();
    16. std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
    17. std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
    18. th.detach();
    19. th1.detach();
    20. }
    21. std::mutex mtx;
    22. void ATaskTest::ThreadDo(int& value) {
    23. while (value < 10000) {
    24. std::unique_lock uniLock(mtx, std::defer_lock);
    25. uniLock.lock();
    26. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    27. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    28. value++;
    29. }
    30. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    31. }
    32. void ATaskTest::ThreadDo1(int& value) {
    33. while (value < 10000) {
    34. std::lock_guard guardLock(mtx);
    35. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    36. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    37. value--;
    38. }
    39. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    40. }

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


    1. std::mutex mtx;
    2. void ATaskTest::ThreadDo(int& value) {
    3. while (value < 10000) {
    4. mtx.lock();
    5. std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
    6. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    7. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    8. value++;
    9. }
    10. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    11. }
    12. void ATaskTest::ThreadDo1(int& value) {
    13. while (value < 10000) {
    14. std::lock_guard<std::mutex> guardLock(mtx);
    15. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    16. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    17. value--;
    18. }
    19. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    20. }


    1. std::mutex mtx;
    2. std::condition_variable cv;
    3. bool isFirst = false;
    4. void ATaskTest::ThreadDo(int& value) {
    5. while (value < 10000) {
    6. mtx.lock();
    7. std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
    8. cv.wait(uniLock, [=] {return !isFirst; });
    9. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    10. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    11. value++;
    12. isFirst = true;
    13. cv.notify_all();
    14. }
    15. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    16. }
    17. void ATaskTest::ThreadDo1(int& value) {
    18. while (value < 10000) {
    19. std::unique_lock<std::mutex> guardLock(mtx);
    20. std::this_thread::sleep_for(std::chrono::milliseconds(10));
    21. cv.wait(guardLock, [=] {return isFirst; });
    22. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    23. value--;
    24. isFirst = false;
    25. cv.notify_all();
    26. }
    27. UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
    28. }

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


    1. std::atomic_int a(1);
    2. void ATaskTest::ThreadDo() {
    3.     while (a < 10000) {
    4.         a++;
    5.         //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    6.     }
    7. }
    8. void ATaskTest::ThreadDo1() {
    9.     while (a < 10000) {
    10.         a--;
    11.         //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    12.     }
    13. }

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

  • 相关阅读:
    代谢组学分析手段(一)
    IO系列第三篇——NIO(Selector)
    互动直播UI设置 之 主播UI
    Delphi 7打造RESTful API客户端
    学校网页设计成品 基于HTML+CSS+JavaScript仿山东财经大学官网 学校班级网页制作模板 校园网页设计成品
    抽象类的规则
    redis探索之缓存击穿、缓存雪崩、缓存穿透
    Tomcat部署及优化
    测试面经 | 从测试螺丝钉到大厂测试开发,三点成长心得和面试经验
    Enzo丨Enzo SAVIEW PLUS AP试剂解决方案
  • 原文地址:https://blog.csdn.net/qqQQqsadfj/article/details/132781804