• CPP(c++) 多线程


    参考链接:
    线程支持库:https://zh.cppreference.com/w/cpp/thread 若能懂此链接,下面都不用看
    1. https://blog.csdn.net/coolwriter/article/details/79883253
    2. https://blog.csdn.net/coolwriter/article/details/79884298

    thread:构造线程

    #include <iostream>       // std::cout  
    #include <thread>         // std::thread  
    
    void thr_function1()  
    {  
        for (int i = 0; i != 10; ++i)  
        {  
            std::cout << "thread 1 print " << i << std::endl;  
        }  
    }  
    
    void thr_function2(int n)  
    {  
        std::cout << "thread 1 print " << n << std::endl;  
    }  
    
    int main()  
    {  
        std::thread t1(thr_function1);     // spawn new thread that calls foo()  
        std::thread t2(thr_function2, 111);  // spawn new thread that calls bar(0)  
        std::cout << "main, foo and bar now execute concurrently...
    ";  
        // synchronize threads:  
        t1.join();                // pauses until first finishes 主线程等待t1线程结束 
        t2.join();               // pauses until second finishes 主线程等待t2线程结束
        std::cout << "thread 1 and htread 2 completed.
    ";  
        return 0;  
    }  

    class thread

    member: http://www.cplusplus.com/reference/thread/thread/
    
    Member types
    get_id  //Thread id (public member type )
    native_handle_type  //Native handle type (public member type )
    
    Member functions:
    Construct thread (public member function )
    Thread destructor (public member function )
    operator=   // Move-assign thread (public member function )
    get_id  // Get thread id (public member function )
    joinable   //Check if joinable (public member function )
    join  //Join thread (public member function )
    detach  //Detach thread (public member function )
    swap //Swap threads (public member function )
    native_handle  //Get native handle (public member function )
    hardware_concurrency [static]  //Detect hardware concurrency (public static member function )

    多线程变量安全
    方式一: 原子操作
    方式二: std::mutex 互斥量

    std::mutex 互斥量: https://zh.cppreference.com/w/cpp/thread/mutex

    #include <iostream>       // std::cout  
    #include <thread>         // std::thread  
    #include <mutex>          // std::mutex  
    
    std::mutex mtx;           // mutex for critical section  
    void print_block(int n, char c) {  
        // critical section (exclusive access to std::cout signaled by locking mtx):
        // mtx.try_lock //尝试锁定互斥,若互斥不可用,则返回  
        mtx.lock();   //锁定互斥,若互斥不可用则阻塞
        for (int i = 0; i<n; ++i) { std::cout << c; }  
        std::cout << '
    ';  
        mtx.unlock();  //解开互斥      
    }  
    int main()  
    {  
        std::thread th1(print_block, 50, '*');  
        std::thread th2(print_block, 50, '$');  
        th1.join();  
        th2.join();  
        return 0;  
    }  

    mutex类4种
    std::mutex,最基本的 Mutex 类。
    std::recursive_mutex,递归 Mutex 类。
    std::time_mutex,定时 Mutex 类。
    std::recursive_timed_mutex,定时递归 Mutex 类。

    recursive_mutex: https://zh.cppreference.com/w/cpp/thread/recursive_mutex
    std::recursive_mutex 与 std::mutex一样,也是一种可以被上锁的对象,但是和 std::mutex 不同的是,std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),
    来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock() 次数和 unlock() 次数相同,除此之外,
    std::recursive_mutex 的特性和 std::mutex 大致相同。

    time_mutex: //https://zh.cppreference.com/w/cpp/thread/timed_mutex
    std::time_mutex 比 std::mutex 多了两个成员函数:
    try_lock_for(): //尝试锁定互斥,若互斥在指定的时限时期中不可用则返回
    try_lock_until(): //尝试锁定互斥,若直至抵达指定时间点互斥不可用则返回

    #include <iostream>       // std::cout  
    #include <chrono>         // std::chrono::milliseconds  
    #include <thread>         // std::thread  
    #include <mutex>          // std::timed_mutex  
    
    std::timed_mutex mtx;  
    void fireworks() {  
      // waiting to get a lock: each thread prints "-" every 200ms:  
      while (!mtx.try_lock_for(std::chrono::milliseconds(200))) {  
        std::cout << "-";  
      }  
      // got a lock! - wait for 1s, then this thread prints "*"  
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));  
      std::cout << "*
    ";  
      mtx.unlock();  
    }
    
    int main ()  
    {  
      std::thread threads[10];  
      // spawn 10 threads:  
      for (int i=0; i<10; ++i)  
        threads[i] = std::thread(fireworks);  
      for (auto& th : threads) th.join();  
      return 0;  
    }  

    Lock 类(两种)
    std::lock_guard: //https://zh.cppreference.com/w/cpp/thread/lock_guard
    与 Mutex RAII 相关,方便线程对互斥量上锁。 //https://zh.cppreference.com/w/cpp/thread/lock_guard
    *值得注意的是,lock_guard 对象并不负责管理 Mutex 对象的生命周期,lock_guard 对象只是简化了 Mutex 对象的上锁和解锁操作,
    ***: 方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;
    ***: 而 lock_guard 的生命周期结束之后,它所管理的锁对象会被解锁。

    #include <iostream>       // std::cout  
    #include <thread>         // std::thread  
    #include <mutex>          // std::mutex, std::lock_guard, std::adopt_lock  
    std::mutex mtx;           // mutex for critical section  
    void print_thread_id(int id) {  
        mtx.lock();  
        std::lock_guard<std::mutex> lck(mtx, std::adopt_lock);  //= mtx.lock() 且在lck 析构时,mtk.unlock 
        std::cout << "thread #" << id << '
    ';  
    }  
    int main()  
    {  
        std::thread threads[10];  
        // spawn 10 threads:  
        for (int i = 0; i<10; ++i)  
            threads[i] = std::thread(print_thread_id, i + 1);  
    
        for (auto& th : threads) th.join();  
    
        return 0;  
    }  

    **** scope_lock:构造时是否加锁是可选的(不加锁时假定当前线程已经获得锁的所有权),析构时自动释放锁,所有权不可转移,对象生存期内不允许手动加锁和释放锁。


    std::unique_lock: //https://zh.cppreference.com/w/cpp/thread/unique_lock
    与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。
    类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。
    unique_lock比lock_guard使用更加灵活,功能更加强大。
    使用unique_lock需要付出更多的时间、性能成本。所以能用lock_guard时,用lock_guard

    class LogFile {
        std::mutex _mu;
        ofstream f;
    public:
        LogFile() {
            f.open("log.txt");
        }
        ~LogFile() {
            f.close();
        }
        void shared_print(string msg, int id) {
    
            std::unique_lock<std::mutex> guard(_mu);//如果 guard(_mu, std::defer_lock); 表示不上锁
            //do something 1
            guard.unlock(); //临时解锁
    
            //do something 2
    
            guard.lock(); //继续上锁
            // do something 3
            f << msg << id << endl;
            cout << msg << id << endl;
            // 结束时析构guard会临时解锁
            // 这句话可要可不要,不写,析构的时候也会自动执行
            // guard.ulock();
        }
    
    };


    condition_variable

    类是同步原语 //https://zh.cppreference.com/w/cpp/thread/condition_variable
    能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable 。
    当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。

    #include <iostream>                // std::cout
    #include <thread>                // std::thread
    #include <mutex>                // std::mutex, std::unique_lock
    #include <condition_variable>    // std::condition_variable
    
    std::mutex mtx; // 全局互斥锁.
    std::condition_variable cv; // 全局条件变量.
    bool ready = false; // 全局标志位.
    
    void do_print_id(int id)
    {
        std::unique_lock <std::mutex> lck(mtx);
        while (!ready) // 如果标志位不为 true, 则等待...
            cv.wait(lck); // 当前线程被阻塞, 当全局标志位变为 true 之后,此外还有 wait for ,wait until 等语句
        // 线程被唤醒, 继续往下执行打印线程编号id.
        std::cout << "thread " << id << '
    ';
    }
    
    void go()
    {
        std::unique_lock <std::mutex> lck(mtx);
        ready = true; // 设置全局标志位为 true.
        cv.notify_all(); // 唤醒所有线程.
        //notify_one 通知一个等待的线程 
    }
    
    int main()
    {
      std::thread threads[10];
      // spawn 10 threads:
      for (int i = 0; i < 10; ++i)
          threads[i] = std::thread(do_print_id, i);
      std::cout << "10 threads ready to race...
    ";
      go(); // go!
      for (auto & th:threads)
        th.join();
      return 0;
    }

    结果:

    10 threads ready to race...
    thread 1
    thread 0
    thread 2
    thread 3
    thread 4
    thread 5
    thread 6
    thread 7
    thread 8
    thread 9

  • 相关阅读:
    【nginx】ubuntu 安装最新版本nginx
    【Linux】dpkg: error processing package XXX (configure) 解决方法
    Ubuntu 搭建文件服务器 (wget 浏览器均可下载)
    GitStats 统计Git所有提交记录工具
    Effective C++ 笔记 —— Item 51: Adhere to convention when writing new and delete.
    Effective C++ 笔记 —— Item 53: Pay attention to compiler warnings.
    Effective C++ 笔记 —— Item 50: Understand when it makes sense to replace new and delete.
    Effective C++ 笔记 —— Item 47: Use traits classes for information about types.
    Effective C++ 笔记 —— Item 45: Use member function templates to accept "all compatible types."
    Effective C++ 笔记 —— Item 46: Define nonmember functions inside templates when type conversions are desired.
  • 原文地址:https://www.cnblogs.com/heimazaifei/p/12176724.html
Copyright © 2020-2023  润新知