当前位置: 首页 > article >正文

多线程--参数传递之间的关系

在C++中创建线程时,传递参数的方式会影响参数的生命周期、线程的安全性和性能。以下是几种常见的传递方式及其适用情况:

1. 值传递

值传递会创建参数的副本,并在线程函数内部使用该副本。这种方式可以避免线程之间的竞态条件,因为每个线程都有自己独立的参数副本。

适用情况

  • 参数是简单的基本类型(如整数、浮点数等)或小型结构体。
  • 你希望每个线程都有参数的独立副本,不会影响其他线程。
  • 参数的拷贝开销不大。
#include <iostream>
#include <thread>

void threadFunction(int value) {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    int value = 42;
    std::thread t(threadFunction, value);
    t.join();
    return 0;
}

2. 引用传递

引用传递允许线程直接访问原始参数,可以避免拷贝大对象的开销。但这也意味着如果主线程修改了参数,子线程可能会遇到未定义行为。

适用情况

  • 参数是大型对象,拷贝开销很大。
  • 确保参数在整个线程执行期间保持有效(主线程不会销毁或修改该参数)。
  • 需要在多个线程间共享数据,并通过同步机制(如互斥锁)来保护数据
#include <iostream>
#include <thread>

void threadFunction(int& value) {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    int value = 42;
    std::thread t(threadFunction, std::ref(value));
    t.join();
    return 0;
}

3. 指针传递

指针传递和引用传递类似,也允许线程直接访问原始参数。但需要注意指针的生命周期管理,避免悬空指针。

适用情况

  • 参数是动态分配的对象,传递指针避免拷贝。
  • 需要传递数组等数据结构,使用指针进行操作
  • 确保指针在整个线程执行期间保持有效,避免悬空指针。
#include <iostream>
#include <thread>

void threadFunction(int* value) {
    std::cout << "Value: " << *value << std::endl;
}

int main() {
    int value = 42;
    std::thread t(threadFunction, &value);
    t.join();
    return 0;
}

小结

  • 值传递:适用于简单类型和小型结构体,避免竞态条件。
  • 引用传递:适用于大型对象,共享数据时需要同步机制。
  • 指针传递:适用于动态分配的对象和数组,需注意指针的生命周期管理。

选择合适的传递方式取决于具体的使用场景和性能需求。

std::thread是不可复制的,但可以移动。push_back使用了移动语义来避免拷贝临时对象。
#include <iostream>
#include <thread>
#include <list>
#include <vector>

using namespace std;

/**
 * 读写案例代码演示
 *
 */
namespace s1 {
    class A {
    public:
        // 把收到的消息(玩家命令)放入到一个队列
        void inMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                msgRecvQueue.push_back(i);
            }
        }
        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                if (!msgRecvQueue.empty()) {
                    // 消息队列不为空
                    int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                    msgRecvQueue.pop_front();
                }
                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            }
            cout << "end " << endl;
        }
    private:
        std::list<int> msgRecvQueue;
    };
}

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

using namespace std;


#define DIELOCK

/**
 * 互斥量概念、用法、死锁演示及解决详解
 *
 */
namespace s2 {
    class A {
    public:
        // 把收到的消息(玩家命令)放入到一个队列
        void inMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                /**
                 * 加锁解锁要保护的数据
                 */
#ifdef DIELOCK
                std::lock(my_mutex1, my_mutex2); // 解决死锁问题
                std::lock_guard<std::mutex> sbGuard1(my_mutex1, std::adopt_lock);
                std::lock_guard<std::mutex> sbGuard2(my_mutex2, std::adopt_lock);
                //                my_mutex1.lock();
                //                my_mutex2.lock();

                msgRecvQueue.push_back(i);
                //                my_mutex2.unlock();
                //                my_mutex1.unlock();

#endif

#ifndef DIELOCK
                //                my_mutex.lock();
                {
                    // scope
                    lock_guard<std::mutex> sbGuard(my_mutex);
                    msgRecvQueue.push_back(i);
                }
                my_mutex.unlock();
#endif
            }
        }

        bool outMsgLULProc(int& command) {

#ifdef DIELOCK
            //            my_mutex2.lock();
            //            my_mutex1.lock();
            std::lock(my_mutex1, my_mutex2); // 解决死锁问题
            // 参数std::adopt_lock 表示不用再lock了
            std::lock_guard<std::mutex> sbGuard1(my_mutex1, std::adopt_lock);
            std::lock_guard<std::mutex> sbGuard2(my_mutex2, std::adopt_lock);

            if (!msgRecvQueue.empty()) {
                // 消息队列不为空
                int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                msgRecvQueue.pop_front();
                //                my_mutex1.unlock();
                //                my_mutex2.unlock();
                return true;
            }
            //            my_mutex1.unlock();
            //            my_mutex2.unlock();
            return false;
#endif

#ifndef DIELOCK
            //            my_mutex.lock();
            //            std::lock_guard<std::mutex> sbGuard(my_mutex); //用了lock_guard 就不能用unlock和lock了
            if (!msgRecvQueue.empty()) {
                // 消息队列不为空
                int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                msgRecvQueue.pop_front();
                //                my_mutex.unlock();  // 这个分支也要有unlock(),否则有可能会一直锁住
                return true;
            }
            //            my_mutex.unlock();
            return false;
#endif
        }
        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            int command = 0;
            for (int i = 0; i < 100000; ++i) {
                bool result = outMsgLULProc(command);
                if (result) {
                    cout << "outMsgRecvQueue()执行、取出一个元素" << command << endl;
                }
                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            }
            cout << "end " << endl;
        }
    private:
        std::list<int> msgRecvQueue;
        std::mutex my_mutex;
        std::mutex my_mutex1;
        std::mutex my_mutex2;
    };
}

/**
 * unique_lock 详解
 */
namespace s3 {
    class A {
    public:
        std::unique_lock<std::mutex> rtn_unique_lock() {
            std::unique_lock<std::mutex> tmpGuard(my_mutex);
            return tmpGuard; // 返回临时对象,调用unique_lock 移动构造函数
        }
        // 把收到的消息(玩家命令)放入到一个队列
        void inMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                /**
                 * 加锁解锁要保护的数据
                 */
                 //                lock_guard<std::mutex> sbGuard(my_mutex);
                                 // unique_lock 可以完全取代 lock_guard
                 //                my_mutex.lock();
                 //                unique_lock<std::mutex> sbGuard1(my_mutex);
                                 // 移动语义 这个时候就直接把所有权转移到了sbGuard2了
                 //                unique_lock<std::mutex> sbGuard2(std::move(sbGuard1));
                                 // 也可以通过返回
                unique_lock<std::mutex> sbGuard2 = rtn_unique_lock();
                // 解除关系
//                std::mutex *ptx = sbGuard1.release();
                std::mutex* ptx = sbGuard2.release();
                msgRecvQueue.push_back(i);
                // 这里必须手动解除
                ptx->unlock();
                // 自己有责任解锁
//                unique_lock<std::mutex> sbGuard1(my_mutex,std::adopt_lock);
//                unique_lock<std::mutex> sbGuard1(my_mutex,std::try_to_lock); //使用这个第二参数 不能再之前lock 否则会卡住
                // 如果拿到锁的话
//                if(sbGuard1.owns_lock()){
//                    cout << "inMsgRecvQueue 执行,拿到锁头..." << endl;
//                    msgRecvQueue.push_back(i);
//                }
//                else{
//                    cout << "inMsgRecvQueue 执行,但是没有拿到锁头..." << endl;
//                }
//                unique_lock<std::mutex> sbGuard1(my_mutex,std::defer_lock); // 初始化一个额没有加锁的mymutex
//                sbGuard1.lock(); // 自己加锁
//                // 有一些非共享代码要处理 可以先unlock()
//                sbGuard1.unlock();
//                sbGuard1.lock(); // 自己加锁
//                if(sbGuard1.try_lock()){
//                    cout << "inMsgRecvQueue 执行,拿到锁头..." << endl;
//                    msgRecvQueue.push_back(i);
//                }
//                else{
//                    cout << "inMsgRecvQueue 执行,但是没有拿到锁头..." << endl;
//                }
//                msgRecvQueue.push_back(i);
//                sbGuard1.unlock();
            }
        }

        bool outMsgLULProc(int& command) {
            //            std::lock_guard<std::mutex> sbGuard(my_mutex); //用了lock_guard 就不能用unlock和lock了
            unique_lock<std::mutex> sbGuard1(my_mutex);

            //            std::chrono::milliseconds dura(2000);      // 20s
            //            std::this_thread::sleep_for(dura);              // 线程休息20s 这回导致另外一个线程也会等待
            if (!msgRecvQueue.empty()) {
                // 消息队列不为空
                int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                msgRecvQueue.pop_front();
                return true;
            }
            return false;
        }

        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            int command = 0;
            for (int i = 0; i < 100000; ++i) {
                bool result = outMsgLULProc(command);
                if (result) {
                    cout << "outMsgRecvQueue()执行、取出一个元素" << command << endl;
                }
                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            }
            cout << "end " << endl;
        }
    private:
        std::list<int> msgRecvQueue;
        std::mutex my_mutex;
        std::mutex my_mutex1;
        std::mutex my_mutex2;
    };
}

/**
 * 单例设计模式分析
 * 线程安全
 * call_once()
 */
namespace s4 {
    // 单线程情况下
    namespace edition1 {
        class MyCAS {
        private:
            MyCAS() {} //私有化构造函数
        private:
            static MyCAS* m_instance;
        public:
            static MyCAS* GetInstance() {
                // 这里多线程下不安全
                if (m_instance == nullptr) {
                    // 两个线程可能同时执行到这里,这样不好
                    m_instance = new MyCAS();
                    // 创建一个静态类对象
                    static GarbageCollection c;
                }
                return m_instance;
            }

            void func() {
                cout << "test" << endl;
            }

            // 引入一个类,对new的对象进行回收
            class GarbageCollection {
            public:
                ~GarbageCollection() {
                    if (MyCAS::m_instance) {
                        // 连个线程可能同时
                        delete MyCAS::m_instance;
                        MyCAS::m_instance == nullptr;
                    }
                }
            };
        };
    }
    // 加锁版本
    namespace edition2 {
        class MyCAS {
        private:
            MyCAS() {} //私有化构造函数
        private:
            static MyCAS* m_instance;
            static std::mutex resource_mutex;
        public:
            static MyCAS* GetInstance() {
                // 双重加锁,提高效率
                if (m_instance == nullptr) {
                    // 加锁
                    std::unique_lock<std::mutex> sbGuard(MyCAS::resource_mutex);
                    if (m_instance == nullptr) {
                        m_instance = new MyCAS();
                        // 创建一个静态类对象
                        static GarbageCollection c;
                    }
                }
                return m_instance;
            }
            void func() {
                cout << "test" << endl;
            }
            // 引入一个类,对new的对象进行回收
            class GarbageCollection {
            public:
                ~GarbageCollection() {
                    if (MyCAS::m_instance) {
                        // 连个线程可能同时
                        delete MyCAS::m_instance;
                        MyCAS::m_instance == nullptr;
                    }
                }
            };
        };
        MyCAS* MyCAS::m_instance = nullptr;
        std::mutex MyCAS::resource_mutex;
    }

    namespace callOnce {
        class MyCAS {
        private:
            MyCAS() {} //私有化构造函数
        private:
            static MyCAS* m_instance;
            static std::mutex resource_mutex;
            static std::once_flag g_flag;
            static void CreateInstance() {
                cout << "createInstance()被执行了" << endl;
                m_instance = new MyCAS();
                static GarbageCollection c;
            }
        public:
            static MyCAS* GetInstance() {
                // 如果两个线程同时执行到这里,其中一个线程执行CreateInstance完毕后,才会执行另一个线程
                std::call_once(g_flag, CreateInstance);
                return m_instance;
            }
            void func() {
                cout << "test" << endl;
            }
            // 引入一个类,对new的对象进行回收
            class GarbageCollection {
            public:
                ~GarbageCollection() {
                    if (MyCAS::m_instance) {
                        // 连个线程可能同时
                        delete MyCAS::m_instance;
                        MyCAS::m_instance == nullptr;
                    }
                }
            };
        };
        MyCAS* MyCAS::m_instance = nullptr;
        std::once_flag MyCAS::g_flag; // 系统定义的标记
    }

    // 线程入口函数
    void myThread() {
        cout << "我的线程开始执行了" << endl;
        edition2::MyCAS::GetInstance(); // 这里可能有问题
        cout << "我的线程执行完毕" << endl;
        return;
    }
    void myThread2() {
        cout << "我的线程开始执行了" << endl;
        callOnce::MyCAS::GetInstance(); // 这里可能有问题
        cout << "我的线程执行完毕" << endl;
        return;
    }
}

/**
 *  condition_variable、wait、notify_one、notify_all
 *
 *  提高效率
 *
 */
 // 要包含这个头文件
#include <condition_variable>

namespace s5 {
    class A {
    public:
        // 把收到的消息(玩家命令)放入到一个队列
        void inMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                unique_lock<std::mutex> sbGuard(my_mutex);
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                msgRecvQueue.push_back(i);
                // 通知其他某一个线程,将wait()唤醒,但是outMsgRecvQueue正处理一个事务,需要处理一段时间,而不是正卡在wait()
                // 那么此时 notify_one() 可能没有效果,还有可能另外一个线程一直都没有获得锁,这是有可能出现的问题
//                my_cond.notify_one();
                my_cond.notify_all(); // 唤醒其他所有线程
            }
        }

        // 得到通知的时候 我们才去取数据
//        bool outMsgLULProc(int& command){
//
//            if(!msgRecvQueue.empty()){
//                std::unique_lock<std::mutex> sbGuard(my_mutex);
//                if(!msgRecvQueue.empty()){
//                    // 消息队列不为空
//                    int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
//                    msgRecvQueue.pop_front();
//                    return true;
//                }
//                return false;
//            }
//        }
        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            int command = 0;
            while (true) {
                std::unique_lock<std::mutex> sbGuard(my_mutex);
                // wait 等一个东西,
                // 如果第二个参数的返回值为false,那么wait将解锁互斥量,并堵塞到本行,
                        // 堵塞到某个线程调用notify_one()成员函数为止
                // 如果第二个参数返回值为true,wait()直接返回
                // 如果没有第二个参数:那就和第二参数为false类似堵塞到某个线程调用notify_one()成员函数为止

                // 当其他线程用notify_one() 将本wait() 唤醒后,wait就开始恢复干活:
                // a):wait() 会尝试再次获取互斥锁,如果获取不到 流程就会卡在这等待获取,如果获取到 ,就继续执行b
                // b):1、如果wait有第二个参数 就判断这个表达式,如果表达式返回false,那wait又对互斥量解锁,再次休眠
                //    2、如果第二个参数返回值为true,那么就会wait就返回,就走下来了,互斥锁还是被锁住了
                //    3、如果没有第二参数,则 wait返回,流程走下来
                my_cond.wait(sbGuard, [this] {
                    if (!msgRecvQueue.empty()) return true;
                    return false;
                    });
                // 流程走到这里来 互斥锁一定是锁住的,至少有一个元素
                command = msgRecvQueue.front();
                msgRecvQueue.pop_front();
                cout << "outMsgRecvQueue()执行、取出一个元素" << command << "线程id:" << std::this_thread::get_id() << endl;
                sbGuard.unlock();

                //
                //处理别的事情...
            }
            //            for(int i = 0; i< 100000; ++i){
            //                bool result = outMsgLULProc(command);
            //                if(result){
            //                    cout << "outMsgRecvQueue()执行、取出一个元素" << command << endl;
            //                }
            //                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            //            }
            //            cout << "end " << endl;
        }
    private:
        std::list<int> msgRecvQueue;
        std::mutex my_mutex;
        std::condition_variable my_cond;  // 条件变量对象
    };
}

/**
 * async、future、packaged_task、promise
 */

#include <future>

namespace s6 {
    class A {
    public:
        int myThread(int myVar) {
            cout << myVar << endl;
            cout << "myThread start " << "thread id: " << std::this_thread::get_id() << endl;
            std::chrono::milliseconds dura(5000); // 休息 5 s
            std::this_thread::sleep_for(dura);
            cout << "myThread end " << "thread id: " << std::this_thread::get_id() << endl;
            return 4;
        }
    };
    int myThread() {
        cout << "myThread start " << "thread id: " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000); // 休息 5 s
        std::this_thread::sleep_for(dura);
        cout << "myThread end " << "thread id: " << std::this_thread::get_id() << endl;
        return 5;
    }

    int myThread2(int myVar) {
        cout << myVar << endl;
        cout << "myThread start " << "thread id: " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000); // 休息 5 s
        std::this_thread::sleep_for(dura);
        cout << "myThread end " << "thread id: " << std::this_thread::get_id() << endl;
        return 3;
    }

    void myThread3(std::promise<int>& temp, int calc) {
        //做一系列复杂的参数
        calc++;
        calc *= 10;
        std::chrono::milliseconds dura(5000); // 休息 5 s
        std::this_thread::sleep_for(dura);

        //计算出结果
        int result = calc;
        // 保存结果
        temp.set_value(result); // 结果保存在temp中
        return;
    }

    void myThread4(std::future<int>& tmpf) {
        auto result = tmpf.get();
        cout << "mythread4 result " << result << endl;
    }
}

#include <atomic>

/**
 * future其他成员函数、shared_future、atomic
 */

namespace s7 {
    int g_mycout = 0;
    std::mutex my_mutex;
    std::atomic<int> g_atomic(0);  // 封装了一个类型为int的原子对象
    std::atomic<bool> g_ifend = { false }; // 线程退出标记
    void myThreadAtomicBool() {
        std::chrono::seconds dura(1);
        while (!g_ifend) {
            // 线程没退出
            cout << "thread bool id " << this_thread::get_id() << "start" << endl;
            std::this_thread::sleep_for(dura);
        }
        cout << "thread bool id " << this_thread::get_id() << "end" << endl;
    }

    void myThreadAtomic() {
        for (int i = 0; i < 1000000; ++i) {
            //            my_mutex.lock();
            g_mycout++;         // 普通变量
            g_atomic++;         // 原子变量、效率比加锁减锁效率高
            //            my_mutex.unlock();
        }
        return;
    }
    int myThread() {
        cout << "myThread start " << "thread id: " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000); // 休息 5 s
        std::this_thread::sleep_for(dura);
        cout << "myThread end " << "thread id: " << std::this_thread::get_id() << endl;
        return 0;
    }
    int myThread2(int temp) {
        cout << temp;
        cout << "myThread2 start " << "thread id: " << std::this_thread::get_id() << endl;
        std::chrono::milliseconds dura(5000); // 休息 5 s
        std::this_thread::sleep_for(dura);
        cout << "myThread2 end " << "thread id: " << std::this_thread::get_id() << endl;
        return 0;
    }
    void myThread3(std::future<int>& tmpf) {
        auto result = tmpf.get(); //第二次会异常,因为get() 是一个移动语义
        cout << "mythread3 result " << result << endl;
    }
    void myThread4(std::shared_future<int>& tmpf) {
        auto result = tmpf.get(); //第二次会异常,因为get() 是一个移动语义
        cout << "mythread3 result " << result << endl;
    }
}

/**
 * 十一、atomic 续谈、async 深入谈
 */
namespace s8 {
    int g_mycout = 0;
    std::mutex my_mutex;
    std::atomic<int> g_atomic(0);  // 封装了一个类型为int的原子对象
    std::atomic<bool> g_ifend = { false }; // 线程退出标记
    void myThreadAtomicBool() {
        std::chrono::seconds dura(1);
        while (!g_ifend) {
            // 线程没退出
            cout << "thread bool id " << this_thread::get_id() << "start" << endl;
            std::this_thread::sleep_for(dura);
        }
        cout << "thread bool id " << this_thread::get_id() << "end" << endl;
    }

    void myThreadAtomic() {
        for (int i = 0; i < 1000000; ++i) {
            //            my_mutex.lock();
            g_mycout++;         // 普通变量
            g_atomic++;         // 原子变量、效率比加锁减锁效率高
            g_atomic += 1;        // 原子变量、效率比加锁减锁效率高
            g_atomic = g_atomic + 1;     // 不是原子操作
            //            my_mutex.unlock();
        }
        return;
    }

    int myThread() {
        cout << "myThread() start " << "thread id :" << this_thread::get_id() << endl;
        return 8;
    }
}


#include <windows.h>

//#define __WINDOWSJQ_
/**
 * 十二、windows 临界区、其他各种mutex互斥量
 */
namespace s9 {
    //  本类自动释放windows下临界区,防止忘记离开临界区
    // RAII (Resource Acquisition is initialization) 资源获取及初始化

    class CWinLock {
    public:
        CWinLock(CRITICAL_SECTION* pCritmp) {
            m_pWinsec = pCritmp;
            EnterCriticalSection(m_pWinsec);
        }
        ~CWinLock() {
            LeaveCriticalSection(m_pWinsec);
        }
    private:
        CRITICAL_SECTION* m_pWinsec;
    };

    class A {
    public:
        void inMsgRecvQueue() {
            for (int i = 0; i < 1000; ++i) {
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                /**
                 * 加锁解锁要保护的数据
                 */
#ifdef __WINDOWSJQ_
                 // 可以重复进临界区,但是进去多少次 就要离开多少次
 //                EnterCriticalSection(&my_winsec);  // 进入临界区
 //                EnterCriticalSection(&my_winsec);   // 进入临界区
                CWinLock vLock(&my_winsec);         // windows 下的自动释放类
                CWinLock vLock1(&my_winsec);         // 也可以进多次
                msgRecvQueue.push_back(i);
                //                LeaveCriticalSection(&my_winsec);   // 离开临界区
                //                LeaveCriticalSection(&my_winsec);   // 离开临界区
#else
                 //                my_recu_mutex.lock();
                 //                my_mutex.lock();
                                 // 解除关系
                 //                testFunc1();
                                 // 超时锁的用法
                std::chrono::milliseconds timeout(100);
                //                my_mutex.try_lock_for(timeout)
                if (my_mutex.try_lock_until(std::chrono::steady_clock::now() + timeout)) {   // 等待100ms 尝试获取锁
                    // 拿到了锁
                    msgRecvQueue.push_back(i);
                    my_mutex.unlock();
                }
                else {
                    cout << "没拿到锁头" << endl;
                    std::chrono::milliseconds timeout(100);
                    std::this_thread::sleep_for(timeout);
                }
                // 这里必须手动解除
//                my_mutex.unlock();
//                my_recu_mutex.unlock();
#endif
            }
        }

        bool outMsgLULProc(int& command) {
#ifdef __WINDOWSJQ_
            EnterCriticalSection(&my_winsec);
            if (!msgRecvQueue.empty()) {
                // 消息队列不为空
                int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                msgRecvQueue.pop_front();
                LeaveCriticalSection(&my_winsec); //这里别忘了
                return true;
            }
            LeaveCriticalSection(&my_winsec);
#else
            //            unique_lock<std::mutex> sbGuard1(my_mutex);
            //            unique_lock<std::recursive_mutex> sbGuard1(my_recu_mutex);
            unique_lock<std::timed_mutex> sbGuard1(my_mutex);
            std::chrono::milliseconds timeout(10000000);
            std::this_thread::sleep_for(timeout);
            if (!msgRecvQueue.empty()) {
                // 消息队列不为空
                int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
                msgRecvQueue.pop_front();
                return true;
            }
#endif
            return false;
        }

        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            int command = 0;
            for (int i = 0; i < 1000; ++i) {
                bool result = outMsgLULProc(command);
                if (result) {
                    cout << "outMsgRecvQueue()执行、取出一个元素" << command << endl;
                }
                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            }
            cout << "end " << endl;
        }

        A() {
#ifdef __WINDOWSJQ_
            InitializeCriticalSection(&my_winsec);
#endif
        }

        /**
         * 假设有一种场景,在testFunc1 需要调用 testFunc2
         */

        void testFunc1() {
            std::lock_guard<std::recursive_mutex> sbGuard(my_recu_mutex);
            testFunc2();
        }

        void testFunc2() {
            std::lock_guard<std::recursive_mutex> sbGuard(my_recu_mutex);
        }
    private:
        std::list<int> msgRecvQueue;
        //        std::mutex my_mutex;
                // 递归互斥锁
        std::recursive_mutex my_recu_mutex;
        std::timed_mutex my_mutex;
        //        std::recursive_timed_mutex my_recu_mutex


#ifdef __WINDOWSJQ_
        CRITICAL_SECTION my_winsec;  // windows 临界区:用之前必须先初始化
#endif
    };

}

/**
 * 十三、补充知识、线程池浅谈、数量谈、总结
 *
 */
namespace s10 {
    class A {
    public:
        // 把收到的消息(玩家命令)放入到一个队列
        void inMsgRecvQueue() {
            for (int i = 0; i < 100000; ++i) {
                unique_lock<std::mutex> sbGuard(my_mutex);
                cout << "inMsgRecvQueue()执行、插入一个元素" << i << endl;
                msgRecvQueue.push_back(i);
                // 通知其他某一个线程,将wait()唤醒,但是outMsgRecvQueue正处理一个事务,需要处理一段时间,而不是正卡在wait()
                // 那么此时 notify_one() 可能没有效果,还有可能另外一个线程一直都没有获得锁,这是有可能出现的问题
                my_cond.notify_one();
                my_cond.notify_one();
                //                my_cond.notify_all(); // 唤醒其他所有线程
            }
        }

        // 得到通知的时候 我们才去取数据
//        bool outMsgLULProc(int& command){
//
//            if(!msgRecvQueue.empty()){
//                std::unique_lock<std::mutex> sbGuard(my_mutex);
//                if(!msgRecvQueue.empty()){
//                    // 消息队列不为空
//                    int command = msgRecvQueue.front();// 返回第一个元素,不检查元素是否存在
//                    msgRecvQueue.pop_front();
//                    return true;
//                }
//                return false;
//            }
//        }
        // 把数据从消息队列中取出的线程
        void outMsgRecvQueue() {
            int command = 0;
            while (true) {
                std::unique_lock<std::mutex> sbGuard(my_mutex);
                // wait 等一个东西,
                // 如果第二个参数的返回值为false,那么wait将解锁互斥量,并堵塞到本行,
                // 堵塞到某个线程调用notify_one()成员函数为止
                // 如果第二个参数返回值为true,wait()直接返回
                // 如果没有第二个参数:那就和第二参数为false类似堵塞到某个线程调用notify_one()成员函数为止

                // 当其他线程用notify_one() 将本wait() 唤醒后,wait就开始恢复干活:
                // a):wait() 会尝试再次获取互斥锁,如果获取不到 流程就会卡在这等待获取,如果获取到 ,就继续执行b
                // b):1、如果wait有第二个参数 就判断这个表达式,如果表达式返回false,那wait又对互斥量解锁,再次休眠
                //    2、如果第二个参数返回值为true,那么就会wait就返回,就走下来了,互斥锁还是被锁住了
                //    3、如果没有第二参数,则 wait返回,流程走下来
                my_cond.wait(sbGuard, [this] {
                    // 解决虚假唤醒
                    if (!msgRecvQueue.empty()) return true;
                    return false;
                    });
                // 流程走到这里来 互斥锁一定是锁住的,至少有一个元素
                command = msgRecvQueue.front();
                msgRecvQueue.pop_front();
                cout << "outMsgRecvQueue()执行、取出一个元素" << command << "线程id:" << std::this_thread::get_id() << endl;
                sbGuard.unlock();

                //
                //处理别的事情...
            }
            //            for(int i = 0; i< 100000; ++i){
            //                bool result = outMsgLULProc(command);
            //                if(result){
            //                    cout << "outMsgRecvQueue()执行、取出一个元素" << command << endl;
            //                }
            //                else cout << "outMsgRecvQueue()执行、消息队列为空" << i << endl;
            //            }
            //            cout << "end " << endl;
        }
    private:
        std::list<int> msgRecvQueue;
        std::mutex my_mutex;
        std::condition_variable my_cond;  // 条件变量对象
    };
}

int main() {

    /**
     * 一、测试双线程读写 对应命名空间 s1
     *
     */
#if 0

    s1::A myObja;
    thread myOutMsgObj(&s1::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myInMsgObj(&s1::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myInMsgObj.join();

#endif

    /**
     *  对应 命名空间 s2
     * 二、保护共享数据、操作时、用代码把共享数据锁住、操作数据、解锁
     *      其他想操作共享数据的操作的线程必须等待解锁
     *  1、互斥量(mutex)基本概念
     *     互斥量是一个类对象、理解成一把锁、多个线程尝试用lock()成员函数加锁这把锁头,
     *     只有一个线程能锁定成功(成功的标志是lock()返回了,否则一直阻塞)
     *     互斥量保护数据不多也不少。少了不能达到保护效果,多了效率低下
     *
     *  2、 lock(),unlock(): 先lock,操作共享数据,然后unlock()
     *      lock()和 unlock(),要成对使用,否则很难排查
     *      为了防止忘记unlock(),引入std::lock_guard的类模板,替你 unlock()
     *  3、 lock_guard 取代lock() 和unlock()
     *      实现原理构造函数执行lock,析构函数执行unlock
     *
     *  4、 死锁:都在等对面解锁,当我们程序中需要加多个锁的时候
     *      cpp中:两把锁(两个互斥量)、金锁 、银锁
     *      出现的例子:两个线程 A、B
     *      1、线程A执行的时候 先把金锁锁住,把金锁lock()、然后它准备去lock()银锁
     *      2、线程B执行了,先把银锁锁住、把银锁lock()、然后它准备去lock() 金锁
     *      此时死锁就发生了
     *      死锁的解决方案:一般加锁顺序一样就不会产生死锁
     *  5、std::lock()函数模板
     *      能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限)
     *      它不存在产生死锁问题:
     *      std::lock() 如果互斥量有一个没锁住、它就在那里等着,等所有互斥量都锁住,才能往下走,如果锁不住,就会把自己锁住的释放掉
     *      要么两个互斥量都锁、要么都不锁住
     *
     *  6、std::lock_guard : 对于多个锁也不想要自己unlock
     */
#if 0
    s2::A myObja;
    thread myOutMsgObj(&s2::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myInMsgObj(&s2::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myInMsgObj.join();
#endif


    /**
     * 对应代码空间 s3
     * 1、 unique_lock 取代lock_guard
     *    unique_lock 是一个类模板 工作中一般lock_guard(推荐使用)
     *    unique_lock 更灵活:效率上差一点、内存占用多一点,问题不是很大
     *
     *
     *
     * 2、unique_lock 第二参数
     *     unique_lock 还支持一些lock_guard 不支持的标志
     *     1、std::adopt_lock : 表示这个互斥量已经被lock了(你必须提前lock,否则报异常),通知lock
     *     2、std::try_to_lock 一个线程卡住20s 另一个线程也会卡住,不灵活:unique_lock 第二个参数 try_to_lock 解决这个问题
     *          我们会尝试用mutex的lock(),去锁住这个mutex 但如果没有锁定成功,我也会立即返回、并不会阻塞在那里
     *          用这个try_to_lcok  之前不能用lock 否则会锁住两次
     *     3、std::defer_lock 第二参数
     *          前提:不能先lock(),否则会异常,defer_lock 表示没有给mutex加锁、初始化了一个没有加锁的 mutex,这样就可以调用
     *          unique_lock 的重要成员函数
     * 3、成员函数
     *      1、lock()
     *      2、unlock()  有一些非共享代码要处理 可以先unlock() 然后再lock()
     *      3、try_lock() 如果拿不到锁 返回false 拿到了 返回true  和defer_lock 搭配使用
     *      4、realease() 返回它所管理的mutex指针 并释放所有权 这个unique_lock 和mutex 不再有关系
     *          这个和unlock() 不一样,放弃unique_lock 和 mutex的绑定关系,之后就要自己管理锁
     *          如果之前是加锁 你需要手动解锁
     *          返回值 是原本的互斥量的指针
     *
     * 4、unique_lock 所有权的传递
     *      1、一个mutex 应该只和一个unique_lock 绑定在一起,这个时候unique_lock 就拥有 一个mutex的所有权
     *          可以转移给其他的unique_lock 对象
     *          unique_lock对象这个mutex的所有权不能复制 mutex也没有复制构造函数
     *         移动语义 这个时候就直接把所有权转移到了sbGuard2了
     *        unique_lock<std::mutex> sbGuard1(my_mutex);
              unique_lock<std::mutex> sbGuard2(std::move(sbGuard1));
           2、也可以作为返回值 :
                unique_lock<std::mutex> sbGuard2 = rtn_unique_lock();


     *
     */
#if 0
    s3::A myObja;
    thread myOutMsgObj(&s3::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myInMsgObj(&s3::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myInMsgObj.join();

#endif

    /**
     *  单例设计模式 分析 对应代码空间 s4
     *    1、设计模式大概谈:
     *          一些代码的写法(比较特殊,和常规写法不太一样):程序灵活,维护起来可能方便,但是别人接管和阅读代码会很痛苦
     *          用设计模式理念写出来的代码很晦涩《head first》,为了应付特别大的项目,把项目的开发经验、模块划分经验,总结
     *          整理成 “ 设计模式 ”,设计模式到中国来,拿着程序往设计模式上套,一个小小的项目,没必要用设计模式,本末倒置
     *          (把简单的写成复杂的,这样不好)
     *    2、单例设计模式:整个项目中,由某个或者某些特殊的类,属于该类的对象,我只能创建一个,多了我创建不了
     *          使用频率高
     *    3、单例设计模式,多线程安全问题分析解决
     *          需要在我们自己创建的线程(而不是主线程)创建MyCAS这个单例类的对象,这种线程可能还不只一个
     *          GetInstance() 要互斥
     *    4、std::call_once():函数模板 C++11 引入的 第二个参数是一个函数名
     *          功能:保证函数只被调用一次 :具备互斥量的能力,效率上比互斥量消耗的资源更少
     *          call_once() 需要和一个标记结合使用 std::once_flag,
     *          call_once() 通过标记决定对应的函数是否执行, 调用call_once成功够,就把std::once_flag 设置为一种已调用
     *          状态
     */
#if 0
     //    s4::edition1::MyCAS* a = s4::edition1::MyCAS::GetInstance();
     //    s4::edition1::MyCAS* b = s4::edition1::MyCAS::GetInstance();
     //    a->func();
     //    b->func();
         // 两个线程入口函数相同,有两条通路 同时执行这个getInstance(),会出问题
     //    std::thread myObj1(s4::myThread);
     //    std::thread myObj2(s4::myThread);
     //    myObj1.join();
     //    myObj2.join();
             // call_once
    std::thread myObj1(s4::myThread2);
    std::thread myObj2(s4::myThread2);
    myObj1.join();
    myObj2.join();

#endif

    /**
     * 1、条件变量:condition_variable、wait()、notify_one()、notify_all
     * 2、   线程 A:等待一个条件满足
     *       线程 B:专门往消息队列中扔消息
     * 3、   condition_variable 实际上是一个类,是一个和条件相关的类,说白了就是等待一个条件达成
     *       这个类需要和互斥量配合工作
     * 4、 上述代码深入思考
     * 5、 notify_all()
     */

#if 0

    s5::A myObja;
    thread myOutMsgObj(&s5::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myOutMsgObj2(&s5::A::outMsgRecvQueue, &myObja); // 为了演示 notify_all()
    thread myInMsgObj(&s5::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myOutMsgObj2.join();
    myInMsgObj.join();

#endif
    /**
     * 一、 async、future、packaged_task、promise
     * 1、希望线程返回一个结果:std::async,std::future
     *      std::async 是一个函数模板,启动一个异步任务 返回一个std::future(类模板) 对象
     *      std::async 就是自动创建一个线程,并开始执行相应的线程入口函数,
     *      返回值std::future对象里面就有线程入口函数所返回的结果(就是线程返回的结果)
     *      可以通过future对象的成员函数get(), 获取结果:std::future提供了一种访问异步操作结果的机制
     *      (这个结果你可能不能马上拿到,但是在不久的将来,线程函数执行完毕的时候,future对象会保存一个值)
     *      get()函数只能调用一次,不能连续调用多次,否则会有异常,而且应该使用get() 或者wait() 等待子线程结束
     *      如果没有get() 程序会等待子线程执行完 再退出,主线程会走到最后等待,不退出
     *      通过额外向std::async() 传递一个参数 参数类型 为std::launch类型(枚举类型)
     *      a) std::launch::deferred 表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用才执行
     *          如果wait或者get没有被调用 线程会执行吗,答:不仅不会执行,线程实际没有创建
     *      b) std::launch::async 表示调用async函数的时候 就开始创建线程
     * 2、package_task 打包任务(类模板)
     *      模板参数 是可调用对象,通过package_task可以把各种可调用对象包装起来,方便将来作为线程入口函数
     *      package_task包装起来的可调用对象还可以直接调用,也就是说它本身也是可以调用
     *
     * 3、std::promise 类模板
     *      我们能够在某个线程中给它赋值,在其他线程中 把这个值取出来用,实现线程之间的通信
     */
#if 0
    s6::A a;
    int tmp = 12;
    cout << "hello world" << "main thread id: " << std::this_thread::get_id() << endl;
    // 自动创建一个线程并执行,result 是一个将来值
//    std::future<int> result = std::async(s6::myThread);
    // 以成员函数作为线程入口,第二个参数用的引用 才保住线程里是一个对象 这里好像没有创建线程,因为线程id是一样的
//    std::future<int> result = std::async(&s6::A::myThread, &a, tmp);
    // 表示延迟调用线程函数 直到get或者wait调用
//    std::future<int> result = std::async(std::launch::deferred,&s6::A::myThread, &a, tmp);
    //    表示调用async函数的时候 就开始创建线程,立即执行线程函数
//    std::future<int> result = std::async(std::launch::async,&s6::A::myThread, &a, tmp);
//    cout << "continue.......!" << endl;
//    int def = 0;
    // result.get() 这里会卡住 等待线程函数执行完毕 拿到结果
//    result.wait(); // 等待线程返回,但是不返回结果 类似于join()
//    cout << result.get() << endl;
//    cout << result.get() << endl;  // 不可以连续两次get()

    /**
     * 1、packaged_task 包装可调用对象
     */
     //    std::packaged_task<int(int)> mypt(s6::myThread2);  // 把函数s6::myThread2() 包装起来
     //    // 可调用对象、参数
     //    std::thread t1(std::ref(mypt),1);  // 线程直接开始执行 ,1 是作为线程入口函数的参数
     //    t1.join();
     //    // 获取返回结果
     //    std::future<int> result = mypt.get_future();
     //    cout << result.get() << endl;

         /**
          * 2、packaged_task 包装lambda 表达式
          */

          //    function<int(int)> ll;
          //    ll = [](int x) -> int {
          //        cout << x << endl;
          //        cout << "myThread start " << "thread id: " << std::this_thread::get_id() << endl;
          //        std::chrono::milliseconds dura(5000); // 休息 5 s
          //        std::this_thread::sleep_for(dura);
          //        cout << "myThread end " << "thread id: " << std::this_thread::get_id() << endl;
          //        return 2;
          //    };
          //    std::packaged_task<int(int)> mypt2(std::ref(ll));

          //    std::thread t2(std::ref(mypt2),1);  // 线程直接开始执行 ,1 是作为线程入口函数的参数
          //    t2.join();
              // 获取返回结果
          //    std::future<int> result2 = mypt2.get_future();
          //    cout << result2.get() << endl;
              /**
               * 3、packaged_task 可以直接调用
               */
               //    mypt2(20);  // 直接调用,相当于函数调用
               //    std::future<int> result3 = mypt2.get_future();
               //    cout << result3.get() << endl;

               /**
                * 容器packaged_task
                */
                //    vector<packaged_task<int(int)>> myTasks;
                //    // 把对象 移到容器里
                //    myTasks.push_back(std::move(mypt2));
                //    std::packaged_task<int(int)> mypt3;
                //    auto iter = myTasks.begin();
                //    mypt3 = std::move(*iter);
                //    myTasks.erase(iter);// 迭代器失效,移除容器里那一项
                //    mypt3(10);
                //    std::future<int> result = mypt3.get_future();
                //    cout << result.get() << endl;
                /**
                 *   4、std::promise
                 */
    std::promise<int> myProm;  // 声明一个对象,保存一个int
    std::thread t1(s6::myThread3, std::ref(myProm), 180);
    t1.join(); // 如果你不等 会报异常

    //获取结果值
    std::future<int> result = myProm.get_future();
    //    cout  << result.get() << endl;
    std::thread t2(s6::myThread4, std::ref(result));
    t2.join();

#endif

    /**
     * 一、 future其他成员函数、shared_future、atomic
     * 1、 future其他成员函数:std::future_status status wait_for()
     * 2、 share_future (类模板)解决多个线程都像得到结果,他的get() 是复制
     * 3、atomic 原子操作:
     *      互斥量:多线程编程中,保护共享数据:先锁,操作共享数据,开锁
     *      有两个线程对一个变量进行操作atomVal共享变量,一个线程读、一个线程写,即使这样也会出问题
     *      原子操作不需要哦用到互斥量加锁(无锁)技术的多线程并发编程方式
     *      在多线程中,不会被打断的程序执行片段,效率比互斥量高,原子操作是不可分割的状态
     *      互斥量是针对一个代码段,往往是一个代码段,而原子操作一般对某个变量操作
     *      std::atomic 类模板,为了封装某个类型的值
     *      // 读线程
     *      int temVal = atomVal;
     *      //写线程
     *      atomVal = 6;
     *
     */

#if 0
     /**
      * 1、std::future_status status wait_for()
      */
    cout << "hello world" << "main thread id: " << std::this_thread::get_id() << endl;
    //     自动创建一个线程并执行,result 是一个将来值
    //    std::future<int> result = std::async(std::launch::async,s7::myThread);
    //    std::future<int> result = std::async(std::launch::deferred,s7::myThread);
    //    cout << "continue.......!" << endl;
    //    std::future_status status = result.wait_for(std::chrono::seconds(6)); // 等待一秒
    //    if(status == std::future_status::timeout){  //超时:我想等待1s,希望你返回,但是你没有返回,所以超时
    //        //表示线程还没执行完,
    //        cout << "超时,线程还没执行完" << endl;
    //    }
    //    else if(status == std::future_status::ready){
    //        cout << " 线程成功返回 " << endl;
    //    }
    //    else if(status == std::future_status::deferred){
    //        cout << "线程被延迟执行" << endl;
    //        // 这个线程函数是在主线程执行的,相当于没有创建子线程
    //        cout << result.get() << endl;
    //    }

    /**
     *  2、share_future,(类模板)解决多个线程都像得到结果,他的get() 是复制
     *  可以get多次
     */
     //    std::packaged_task<int(int)> mypt(s7::myThread2);
     //    std::thread t1(std::ref(mypt),1);
     //    t1.join();
     //    std::future<int> result = mypt.get_future();
     //    std::shared_future<int> result_s(std::move(result));
     //    bool ifcanget = result.valid();
     //    std::shared_future<int> result_s(result.share());
     //    std::shared_future<int> result_s(mypt.get_future()); //通过get_future 构造一个shared_future 对象
     //    auto mythreadRes = result_s.get();
     //    mythreadRes = result_s.get();
     //    ifcanget = result.valid();

     //    std::thread t2(s7::myThread4,std::ref(result_s));
     //    t2.join();
     //    cout << result_s.get() << endl;
     //    cout << result_s.get() << endl;
     //    cout << result_s.get() << endl;

         /**
          * 3、原子操作:atomic
          */
          //    hello worldmain thread id: 1
          //    最后的结果:1607245
          //    over
          //    请按任意键继续. . .
    thread myObj1(s7::myThreadAtomicBool);
    thread myObj2(s7::myThreadAtomicBool);
    std::chrono::seconds dura(5);
    std::this_thread::sleep_for(dura);
    s7::g_ifend = true;
    myObj2.join();
    myObj1.join();

    cout << "最后的结果:" << s7::g_mycout << endl;
    cout << "最后的结果:" << s7::g_atomic << endl;

#endif

    /**
     * atomic 续谈、async 深入谈
     *  1、 atomic 针对 ++、--,+=,&=、|=、^=等一元是可以的,但是对有些操作不是原子操作,所以要注意
     *
     *  2、async
     *      参数详述,async用来创建一异步任务,一般不叫创建一个线程
     *      std::thread() 如果系统资源紧张,那么可能创建线程就会失败,那么执行std::thread(),就会导致整个程序可能崩溃
     *      上述最明显不同的时候,有时候async并不创建线程,而是在get()所在线程中执行线程入口函数
     *      1)如果用std::launch::defferred 作为第一参数
     *          没有创建线程,而是在调用get()时所在线程中执行线程入口函数,如果没有调用则入口函数不会执行
     *      2)如果std::launch::async 作为第一参数,则必须创建一个线程
     *      3)如果同时用 std::launch::async |std::launch::defferred,
     *          意味着可能是std::launch::async
     *             也可能是 std::launch::defferred
     *      4)如果没有默认第一参数 默认是 std::launch::async |std::launch::defferred (不确定)
     *          让系统决定自行决定是同步、还是异步,系统如何决定?
     * 3、std::thread()和 std::async() 的区别
     *      std::thread():一定会创建线程,如果创建失败,程序直接崩溃、返回值不好接,要用全局量或者package_list 或者promise
     *      std::async: 创建异步任务:可能创建线程、可能不创建线程,返回值是std::future<T> 容易拿到返回值,一般不会异常不会
     *      崩溃,因为如果系统紧张,不加额外参数的调用或者std::launch::defferred,那么它不会创建线程,而是在get() 处的线程
     *      执行,如果你强制使用std::launch::async ,可能会导致系统崩溃
     *
     * 4、经验:一个程序里线程数量不宜超过100-200
     *
     * 5、std::async不确定性问题的解决: std::future<int> result = std::async(s8::myThread);
     *      问题焦点在于:异步任务不一定会被执行,要判断有没有被推迟执行,要使用wait_for函数
     *
     */

#if 0
     /**
      * 1、atomic 续谈
      */
      //    thread myObj1(s8::myThreadAtomic);
      //    thread myObj2(s8::myThreadAtomic);
      //
      //    myObj2.join();
      //    myObj1.join();
      //
      //    cout << "最后的结果:" << s8::g_mycout << endl;
      //    cout << "最后的结果:" << s8::g_atomic << endl;

          /**
           * 2、async 深入谈
           * std::thread() 如果系统资源紧张,那么可能创建线程就会失败,那么执行std::thread(),就会导致整个程序可能崩溃
           *
           */
    std::future<int> result = std::async(s8::myThread); // 不确定情况
    //    std::future<int> result = std::async(std::launch::async,s8::myThread);
    //    std::future<int> result = std::async(std::launch::async|std::launch::deferred ,s8::myThread); // 不确定情况
    cout << "continue.......!" << endl;
    //    std::future_status status = result.wait_for(std::chrono::seconds(0)); // 等待一秒
    std::future_status status = result.wait_for(0s); // 等待一秒

    if (status == std::future_status::deferred) {
        cout << "线程被延迟执行,没有开启线程" << endl;
        // 这个线程函数是在主线程执行的,相当于没有创建子线程,这时候手动执行线程函数
        cout << result.get() << endl;
    }
    else if (status == std::future_status::timeout) {  //超时:我想等待1s,希望你返回,但是你没有返回,所以超时
        //表示线程还没执行完,
        cout << "超时,线程还没执行完" << endl;
    }
    else if (status == std::future_status::ready) {
        cout << " 线程成功返回 " << endl;
    }

#endif
    /**
     * 十二、windows 临界区、其他各种mutex互斥量
     * 1、windows 临界区: 在windwos下的临界区,和C++11 mutex非常类似
     *
     * 2、多次进入临界区试验
     *      在同一个线程中,可以重复进去相同的临界区变量,但是也要相应出来几次,C++11 互斥锁不可以
     * 3、自动析构技术,实现windows 下面的临界区
     *
     * 4、recursive_mutex 递归的独占互斥量,当需要多次加锁的时候会用到
     *      std::mutex 独占互斥量
     *      std::recursive_mutex 递归独占互斥量,允许同一个线程,同一个互斥量多次被lock()
     *      也有lock() 和unlock() 递归测试次数有限制
     *
     * 5、带超时的(递归)互斥量std::timed_mutex和 std::recursive_timed_mutex
     *      等待一段时间
     *      1、try_lock_for(),如果等待一段时间拿到了锁或者超时都会继续走下去
     *      2、try_lock_until() 参数是一个未来的时间点,在未来的时间没到的时间段内,如果拿到了锁 流程就走下来
     *                         如果时间到了,还没拿到锁,也会走下来
     *
     *
     */
#if 0
    s9::A myObja;
    thread myOutMsgObj(&s9::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myInMsgObj(&s9::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myInMsgObj.join();

#endif
    /**
     * 十三、补充知识、线程池浅谈、数量谈、总结
     * 1、虚假唤醒
     *      wait(),notify_one(),notify_all()
     *          my_cond.wait(sbGuard,[this]{
                    // 解决虚假唤醒
                    if(!msgRecvQueue.empty()) return true;
                    return false;
                });
        2、atomic<int> a(1);  // 操作原子 就不让任务切换
            void thread(){
                a++;
            }
            while(true){
                cout << a << endl;   // 读atm是原子操作,但是整个操作不是原子操作
                auto atm2 = a;       // 这里是不合法的 没有拷贝构造函数,赋值也不可以
                atomic<int> atm2(atm.load())  // 这里是可以的,读
                auto atm2(atm.load())

                atm2.store(12)       // 写
            }

     */
#if 1

    s10::A myObja;
    thread myOutMsgObj(&s10::A::outMsgRecvQueue, &myObja); // 第二个参数是引用 才可以保证线程里调用的是一个对象
    thread myInMsgObj(&s10::A::inMsgRecvQueue, &myObja);
    myOutMsgObj.join();
    myInMsgObj.join();

#endif
    cout << "main() start " << "main thread id :" << this_thread::get_id() << endl;
    cout << "over " << endl;
    //    system("pause");
    return 0;
}

http://www.kler.cn/a/580489.html

相关文章:

  • react中字段响应式
  • springboot3整合knife4j详细版,包会!(不带swagger2玩)
  • 没有与此调用匹配的重载
  • 量子计算对区块链技术的影响:革新与挑战
  • 开源项目ESP-SparkBot: ESP32-S3 大模型 AI 桌面机器人(复刻分享)
  • 服务端和客户端通信(TCP)
  • OpenAI Whisper:开启语音转文本的智能时代
  • Unity DOTS 从入门到精通之传统 Unity 设计转换为 DOTS 设计
  • 驾培市场与低空经济无人机融合技术详解
  • HTML 表单 (form) 的作用解释
  • 【C++设计模式】第三篇:抽象工厂模式(Abstract Factory)
  • 行为模式---中介者模式
  • MATLAB中movsum函数用法
  • 使用AI一步一步实现若依前端(5)
  • Java直通车系列25【Spring Boot】(核心注解)
  • Spring boot 3.3.1 官方文档 中文
  • monaco-editor/react 自定义高亮
  • vue+dhtmlx-gantt 实现甘特图-快速入门【甘特图】
  • 天梯选拔赛赛后补题
  • Unet实战分割项目:深度学习与医学影像分析