C++多线程(mutex类)(三)

来源:互联网 发布:淘宝列表调成大图 编辑:程序博客网 时间:2024/06/15 14:23

mutex 类
详细方法介绍参见C++ Ref

  • Mutex Types
    Mutex types是lockable type类型,用于保护对特定区域代码的访问。支持操作:lock 和unlock。lock操作用于防止其他thread的访问,unlock操作用于解除lock。C++11中有4种Mutex Type
    • mutex
      • 构造器 constexpr mutex() noexcept; 不支持拷贝构造或者赋值构造
      • 支持lock(),try_lock(),unlock(),native_handle()方法
    • recursive_mutex
      • 与mutex相比,其lock()与try_lock()可以对同一recursive_mutex对象获得多级ownership
    • timed_mutex
      • 额外提供try_lock_for()与try_lock_until()方法。两个方法的含义是在timed_mutex对象被其他线程lock住时,当前线程将会block for duration or to timepoint
    • recursive_timed_mutex 集成了recursive_mutex和timed_mutex特性

lock方法执行区别
- 对任意的mutex type对象,若其(cur_mutex)已被其他thread locked,则调用lock()方法将会进入block,调用try_lock()方法将会失败,返回false;调用try_lock_for/try_lock_until()方法将会block一段时间,在此期间一直等待获取cur_mutex的lock
- 若cur_mutex还没有被任意thread获取lock,则所有lock方法将会获得lock并返回
- 若cur_mutex已被当前thread获取lock,对于mutex对象和timed_mutex对象,调用lock(),try_lock(),try_lock_for(),try_lock_until() 会产生死锁,函数有的会产生Error,有的不会; 若对recursive_mutex和recursive_timed_mutex调用lock(),try_lock(),try_lock_for(),try_lock_until(),将会产生新一级的lock,最后unlock时也需要调用相同数目的unlock方法

  • Locks
    Locks提供了一种管理mutex的机制
    • lock_guard
      • 是一种简单的机制,仅提供构造器和析构器方法
      • 创建时自动上锁,lock_guard析构时自动调用unlock方法
    • unique_lock
      • 相对lock_guard来说,unique_lock更加灵活。创建时自动对mutex对象上锁,析构时自动调用unlock()方法。unique_lock并不管理mutex对象的生命周期,但是mutex对象在lock_guard析构时必须存在。
      • 支持多种形式的构造器,包括初始化以及移动构造
      • 支持lock(),try_lock(),try_lock_for(),try_lock_until(),unlock()方法
      • 支持移动赋值 unique_lock& operator= (unique_lock&& x) noexcept;
      • swap()方法:交换管理的mutex对象和owning state(lock or unlock)
      • release()方法:mutex_type* release() noexcept; 返回指向管理的mutex_type的指针,并且unique_lock释放对mutex 对象的管理权,此后unique_lock不再管理任何mutex 对象
      • owns_lock():返回是否lock住某个mutex对象
      • (): 与owns_lock()功能相同
      • mutex(): 返回指向管理的mutex对象的指针
  • Other Type
  • Functions
    • lock()
      • template <class Mutex1, class Mutex2, class… Mutexes>
        void lock (Mutex1& a, Mutex2& b, Mutexes&… cde);
      • lock 所有Mutex对象,但并不按照特定顺序,若暂时无法lock则将block调用线程
      • 函数返回时保证所有Mutex对象均以被lock,且无死锁产生
      • 若由于exception导致无法lock某Mutex对象,函数在fail前将首先unlock所有已被lock的Mutex对象
    • try_lock()
      • template <class Mutex1, class Mutex2, class… Mutexes> int try_lock (Mutex1& a, Mutex2& b, Mutexes&… cde);
      • 按照顺序依次尝试lock Mutex对象a,b,…,cde直到所有Mutex对象均lock成功或者任一Mutex 对象lock失败(return false or throw exception)。若失败,则将会对所有已经成功lock的Mutex对象执行unlock操作
    • call_once()
      • template <class Fn, class… Args>
        void call_once (once_flag& flag, Fn&& fn, Args&&… args);
      • 该函数为Passive调用,任意线程调用任意fn,若flag相同,则仅做一次调用。
        call_once实例
#include <iostream>       // std::cout#include <thread>         // std::thread, std::this_thread::sleep_for#include <chrono>         // std::chrono::milliseconds#include <mutex>          // std::call_once, std::once_flagusing namespace::std;int winner;void set_winner(int x) { cout << "Enter into set_winner" << endl; winner = x; }//仅执行一次void print_winner(int x) { cout << "Enter into print_winner" << endl; winner = x; }std::once_flag winner_flag;void wait_1000ms(int id) {    // count to 1000, waiting 1ms between increments:    for (int i = 0; i<1000; ++i)        std::this_thread::sleep_for(std::chrono::milliseconds(1));    // claim to be the winner (only the first such call_once on winner_flag is executed):    std::call_once(winner_flag, set_winner, id);    std::call_once(winner_flag, print_winner, 100);//will not execute since winner_flag has been called by call_once}int main(){    std::thread threads[10];    // spawn 10 threads:    for (int i = 0; i<10; ++i)        threads[i] = std::thread(wait_1000ms, i + 1);    std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";    for (auto& th : threads) th.join();    std::cout << "winner thread: " << winner << '\n';    this_thread::sleep_for(chrono::seconds(10));    cout << "call_once after Sleep" <<endl;    thread t(wait_1000ms, 100);    t.join();    cout << "New winner " << winner << endl;//the winner result are always same as before    system("pause");    return 0;}

可能的运行结果

waiting for the first among 10 threads to count 1000 ms...Enter into set_winnerwinner thread: 2call_once after SleepNew winner 2Press any key to continue . . .