当前位置:首页 > 编程笔记 > 正文
已解决

C++多线程学习(二):多线程通信和锁

来自网友在路上 11068106提问 提问时间:2023-11-23 23:48:08阅读次数: 106

最佳答案 问答题库1068位专家为你答疑解惑

参考引用

  • C++11 14 17 20 多线程从原理到线程池实战
  • 代码运行环境:Visual Studio 2019

1. 多线程状态

1.1 线程状态说明

  • 初始化 (lnit):该线程正在被创建
  • 就绪 (Ready):该线程在就绪列表中,等待 CPU 调度
  • 运行 (Running):该线程正在运行
  • 阻塞 (Blocked):该线程被阻塞挂起,Blocked 状态包括
    • pend (锁、事件、信号量等阻塞)
    • suspend (主动 pend)
    • delay (延时阻塞)
    • pendtime (因为锁、事件、信号量时间等超时)
  • 退出 (Exit):该线程运行结束,等待父线程回收其控制块资源
    • 告诉操作系统把该线程相关资源释放,不包含堆中的资源释放

在这里插入图片描述

1.2 竞争状态和临界区

  • 竞争状态 (Race Condition)
    • 多线程同时读写共享数据
  • 临界区 (Critical Section)
    • 读写共享数据的代码片段(lock 和 unlock 之间的代码)

避免竞争状态策略,对临界区进行保护,同时只能有一个线程进入临界区

2. 互斥体和锁

2.1 互斥锁

  • thread_mutex.cpp
    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>using namespace std;static mutex mux;void TestThread() {for (;;){	// 获取锁资源,如果没有则阻塞等待(一次只能有一个线程拿到锁)// 拿锁的原则:尽晚申请、尽早释放//mux.lock();           // 拿锁方式一 if (!mux.try_lock()) {  // 拿锁方式二:可以看到多个进程在竞争拿锁的情况cout << "." << flush;this_thread::sleep_for(100ms);continue;}// 业务代码cout << "=========" << endl;cout << "Test 001" << endl;cout << "Test 002" << endl;cout << "Test 003" << endl;cout << "=========" << endl;mux.unlock();  // 如果忘记释放锁,则会导致死锁,所有线程都在等待this_thread::sleep_for(1000ms);}
    }int main(int argc, char* argv[]) {// 同时创建 10 个线程for (int i = 0; i < 10; i++) {thread th(TestThread);th.detach();}getchar();return 0;
    }
    

2.2 线程抢占不到资源

  • thread_mutex2.cpp
    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>using namespace std;static mutex mux;void ThreadMainMux(int i) {for (;;){	mux.lock();cout << i << "[in]" << endl;this_thread::sleep_for(1000ms);mux.unlock();// 防止 unlock() 还未释放完全就进入下一个 lock(),导致其他线程拿不到锁this_thread::sleep_for(1ms);}
    }int main(int argc, char* argv[]) {// 同时创建 3 个线程for (int i = 0; i < 3; i++) {thread th(ThreadMainMux, i + 1);th.detach();}getchar();return 0;
    }
    

2.3 超时锁 timed_mutex 应用

  • 可以记录锁的获取情况,多次超时,可以记录日志,获取错误情况,避免长时间死锁
  • timed_mutex.cpp
    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>using namespace std;timed_mutex tmux;  // 支持超时的互斥锁void ThreadMainTime(int i) {for (;;){	if (!tmux.try_lock_for(chrono::milliseconds(500))) {cout << i << "[try_lock_for timeout]" << endl;continue;}cout << i << "[in]" << endl;this_thread::sleep_for(2000ms);tmux.unlock();// 防止 unlock() 还未释放完全就进入下一个 lock(),导致其他线程拿不到锁this_thread::sleep_for(1ms);}
    }int main(int argc, char* argv[]) {getchar();// 同时创建 3 个线程for (int i = 0; i < 3; i++) {thread th(ThreadMainTime, i + 1);th.detach();}getchar();return 0;
    }
    

2.4 递归锁 recursive_mutex(可重入)

  • 同一个线程中的同一把锁可以锁多次,避免一些不必要的死锁
  • 组合业务:用到同一个锁
  • recursive_mutex.cpp
    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>using namespace std;recursive_mutex rmux;  // 支持可重入的互斥锁void Task1() {rmux.lock();cout << "task1 [in]" << endl;rmux.unlock();
    }void Task2() {rmux.lock();cout << "task2 [in]" << endl;rmux.unlock();
    }void ThreadMainRec(int i) {for (;;){// 加锁几次对应的也要解锁几次rmux.lock();Task1();cout << i << "[in]" << endl;this_thread::sleep_for(2000ms);Task2();rmux.unlock();this_thread::sleep_for(1ms);}
    }int main(int argc, char* argv[]) {// 同时创建 3 个线程for (int i = 0; i < 3; i++) {thread th(ThreadMainRec, i + 1);th.detach();}getchar();return 0;
    }
    

2.5 共享锁 shared_mutex(解决读写问题)

  • c++14 共享超时互斥锁 shared_timed_mutex
  • 如果只有写时需要互斥,读取时不需要,用普通的锁的话如何做
  • 按照如下代码,读取只能有一个线程进入,在很多业务场景中,没有充分利用 CPU 资源

在这里插入图片描述

  • shared_mutex.cpp
    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>
    #include <shared_mutex>using namespace std;shared_timed_mutex stmux;  // 支持可重入的共享锁 C++14// 读取线程
    void ThreadRead(int i) {for (;;){stmux.lock_shared();cout << i << " Read" << endl;this_thread::sleep_for(500ms);stmux.unlock_shared();this_thread::sleep_for(1ms);}
    }// 写入线程
    void ThreadWrite(int i) {for (;;){stmux.lock_shared();  // 只要没有锁定互斥锁,共享锁都是立即返回// 读取数据stmux.unlock_shared();// 互斥锁 写入(同时只能一个线程写入),共享锁和互斥锁都不能进入stmux.lock();  cout << i << " Write" << endl;this_thread::sleep_for(300ms);stmux.unlock();this_thread::sleep_for(1ms);}
    }int main(int argc, char* argv[]) {for (int i = 0; i < 3; i++) {thread th(ThreadWrite, i + 1);th.detach();}for (int i = 0; i < 3; i++) {thread th(ThreadRead, i + 1);th.detach();}getchar();return 0;
    }
    
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"C++多线程学习(二):多线程通信和锁":http://eshow365.cn/6-42089-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!