2.1 多线程的状态及其切换流程分析

2.1.1 线程状态说明

  • 初始化 init:该线程正在被创建
  • 就绪 ready:该线程在就绪列表中,等待CPU调度
  • 运行 running:该线程正在运行
  • 阻塞 blocked:该线程被阻塞挂起。blocked状态包括:pend(锁、事件、信号量等阻塞)、suspend(主动pend)、delay(延迟阻塞)、pendtime(因为锁、事件、信号量时间等超时等待)。
  • 退出 exit:该线程运行结束,等待父线 程回收其控制块资源

image.png

2.2 竞争状态和临界区介绍_互斥锁mutex代码

  • 竞争状态 race condition
    多线程同时读写共享数据
  • 临界区 critical section
    读写共享数据的代码片段

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

2.2.1 互斥体和锁

2.2.1 互斥锁 mutex

  • 不用锁的情况演示 ```cpp

    include

    include

    include

using namespace std;

void TestThread() { cout << “==============================” << endl; cout << “test 001” << endl; cout << “test 002” << endl; cout << “test 003” << endl; cout << “==============================” << endl; }

int main(int argc, char* argv[]) { for (int i = 0; i < 3; i++) { thread th(TestThread); th.detach(); }

  1. this_thread::sleep_for(2000ms);
  2. return 0;

}

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2878535/1615703821518-30d4712b-433f-4128-b0b2-498246f4d59b.png#align=left&display=inline&height=413&margin=%5Bobject%20Object%5D&name=image.png&originHeight=413&originWidth=1405&size=37963&status=done&style=none&width=1405)
  2. - 期望输出一整段内容
  3. - lock() unlock()
  4. ```cpp
  5. #include <thread>
  6. #include <iostream>
  7. #include <string>
  8. #include <mutex>
  9. using namespace std;
  10. static mutex mux;
  11. void TestThread()
  12. {
  13. for (;;) {
  14. // 获取锁资源,如果没有则阻塞等待 完整输出
  15. mux.lock();
  16. cout << "==============================" << endl;
  17. cout << "test 001" << endl;
  18. cout << "test 002" << endl;
  19. cout << "test 003" << endl;
  20. cout << "==============================" << endl;
  21. mux.unlock();
  22. }
  23. }
  24. int main(int argc, char* argv[])
  25. {
  26. for (int i = 0; i < 10; i++)
  27. {
  28. thread th(TestThread);
  29. th.detach();
  30. }
  31. this_thread::sleep_for(1000ms);
  32. return 0;
  33. }

image.png

  • try_lock() 和 unlock()
    #include <iostream>
    #include <mutex>
    #include <string>
    #include <thread>
    //Linux -lpthread
    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[])
    {
    for (int i = 0; i < 10; i++) {
       thread th(TestThread);
       th.detach();
    }
    getchar();
    return 0;
    }
    
    image.png

    2.2.2 互斥锁的坑:线程抢占不到资源

    ```cpp

    include

    include

    include

using namespace std;

static mutex mux;

void ThreadMainMux(int i) { for (;;) { mux.lock(); cout << i << “ [in]” << endl; this_thread::sleep_for(1000ms); mux.unlock(); } }

int main(int argc, char* argv[]) { for (int i = 0; i < 3; i++) { thread th(ThreadMainMux, i + 1); th.detach(); } getchar(); return 0; }

![image.png](https://cdn.nlark.com/yuque/0/2021/png/2878535/1615704026854-48cd57de-6db8-4afd-b90e-c81da823fb6c.png#align=left&display=inline&height=413&margin=%5Bobject%20Object%5D&name=image.png&originHeight=413&originWidth=1403&size=27511&status=done&style=none&width=1403)<br />这样能看到某个进程占用太长时间,所以是有问题的。故需要在释放锁后等待一会,即:
```cpp
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;

static mutex mux;

void ThreadMainMux(int i) {
    for (;;) {
        mux.lock();
        cout << i << " [in]" << endl;
        this_thread::sleep_for(1000ms);
        mux.unlock();
    }
    this_thread::sleep_for(1ms);
}


int main(int argc, char* argv[]) {

    for (int i = 0; i < 3; i++) {
        thread th(ThreadMainMux, i+1);
        th.detach();
    }
    getchar();
    return 0;
}

image.png

2.3 互斥锁的坑_线程抢占不到资源原因

2.3.1 超时锁应用 timed_mutex 避免长时间死锁

#include <iostream>
#include <mutex>
#include <thread>

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();
        this_thread::sleep_for(1ms);
    }
}

int main()
{
    for (int i = 0; i < 3; i++) {
        thread th(ThreadMainTime, i + 1);
        th.detach();
    }
    getchar();
    return 0;
}

image.png

2.4 递归锁(可重入)recursive_mutex和 recursive_timed_mutex用于业务组合

  • 同一个线程中的同一把锁可以锁多次。避免了一些不必要的死锁
  • 组合业务 用到同一个锁 ```cpp

    include

    include

    include

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 TreadMainSec(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() { for (int i = 0; i < 3; i++) { thread th(TreadMainSec, i + 1); th.detach(); } getchar(); return 0; }

![image.png](https://cdn.nlark.com/yuque/0/2021/png/2878535/1615705020080-a79380a9-7f9f-4503-9bb6-47ed2c84a69b.png#align=left&display=inline&height=414&margin=%5Bobject%20Object%5D&name=image.png&originHeight=414&originWidth=1404&size=31804&status=done&style=none&width=1404)

<a name="1gBms"></a>
# 2.5 共享锁 shared_mutex

- C++14 共享超时互斥锁 shared_timed_mutex
- C++17 共享互斥 shared_mutex
- 如果只有写时需要互斥,读取时不需要,用普通的锁的话如何做
- 按照如下代码,读取时只能有一个线程进入,在很多业务场景中,没有充分利用CPU资源
```cpp
// 读取 同时只能有一个线程读取
mux.lock();
cout << share << endl;
mux.unlock();

// 写入
mux.lock();
shared++;
mux.unlock();
#include <iostream>
#include <mutex>
#include <shared_mutex>
// C++14
// #include <shared_timed_mutex>

using namespace std;

shared_mutex smux;

void ThreadRead(int i)
{
    for (;;) {
        smux.lock_shared();
        cout << i << "Read" << endl;
        this_thread::sleep_for(500ms);
        smux.unlock_shared();
        this_thread::sleep_for(1ms);
    }
}

void ThreadWrite(int i)
{
    for (;;) {
        // smux.lock_shared();
        // 读取数据
        // smux.unlock_shared();
        smux.lock(); // 互斥锁 写入
        cout << i << "Write" << endl;
        this_thread::sleep_for(300ms);
        smux.unlock(); // 互斥锁 写入
        this_thread::sleep_for(1ms); // 防止资源无限被占用
    }
}

int main()
{
    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;
}

image.png