zoukankan      html  css  js  c++  java
  • C++笔记-并发编程 异步任务(async)

    转自 https://www.cnblogs.com/diysoul/p/5937075.html

    参考:https://zh.cppreference.com/w/cpp/thread/lock_guard

    创建 lock_guard 对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥。

    lock_guard 类不可复制。

    模板形参

    Mutex - 要锁定的互斥。类型必须满足基础可锁 (BasicLockable) 要求

    成员类型

     
    成员类型 定义
    mutex_type Mutex

    成员函数

    构造 lock_guard ,可选地锁定给定的互斥 
    (公开成员函数)
    析构 lock_guard 对象,解锁底层互斥 
    (公开成员函数)
    operator=
    [被删除]
    不可复制赋值 
    (公开成员函数)

    示例

    #include <thread>
    #include <mutex>
    #include <iostream>
     
    int g_i = 0;
    std::mutex g_i_mutex;  // 保护 g_i
     
    void safe_increment()
    {
        std::lock_guard<std::mutex> lock(g_i_mutex);
        ++g_i;
     
        std::cout << std::this_thread::get_id() << ": " << g_i << '
    ';
     
        // g_i_mutex 在锁离开作用域时自动释放
    }
     
    int main()
    {
        std::cout << "main: " << g_i << '
    ';
     
        std::thread t1(safe_increment);
        std::thread t2(safe_increment);
     
        t1.join();
        t2.join();
     
        std::cout << "main: " << g_i << '
    ';
    }

    可能的输出:

    main: 0
    140641306900224: 1
    140641298507520: 2
    main: 2

    C++并发编程 异步任务(async)

    线程基本的互斥和同步工具类, 主要包括:
      std::mutex 类
      std::recursive_mutex 类
      std::timed_mutex 类
      std::recursive_timed_mutex 类
      std::lock_guard 类型模板
      std::unique_lock 类型模板
      std::lock 函数模板
      std::once_flag 类
      std::call_once 函数模板

    std::mutex 类

      std::mutex 上锁须要调用 lock() 或 try_lock(), 当有一个线程获取了锁, 其它线程想要取得此对象的锁时, 会被阻塞(lock)或失败(try_lock). 当线程完成共享数据的保护后, 需要调用 unlock 进行释放锁.
      std::mutex 不支嵌套, 如果两次调用 lock, 会产生未定义行为.

    std::recursive_mutex 类

    使用方法同 std::mutex, 但 std::recursive_mutex 支持一个线程获取同一个互斥量多次,而没有对其进行一次释放. 但是同一个线程内, lock 与 unlock 次数要相等, 否则其它线程将不能取得任何机会.
    其原理是, 调用 lock 时, 当调用线程已持有锁时, 计数加1; 调用 try_lock 时, 尝试取得锁, 失败时不会阻塞, 成功时计数加1; 调用 unlock 时, 计数减1, 如果是最后一个锁时, 释放锁.
    需要注意的是: 调用 try_lock时, 如果当前线程未取得锁, 即使没有别的线程取得锁, 也有可能失败.

    std::timed_mutex 类

    std::timed_mutex 在 std::mutex 的基础上支持让锁超时. 上锁时可以调用 try_lock_for, try_lock_until 设置超时值.
    try_lock_for 的参数是需要等待的时间, 当参数小于等于0时会立即返回, 效果和使用 try_lock 一样. 
    try_lock_until 传入的参数不能小于当前时间, 否则会立即返回, 效果和使用 try_lock 一样. 实际上 try_lock_for 内部也是调用 try_lock_until 实现的.
    tm.try_lock_for(std::chrono::milliseconds(1000)) 与 tm.try_lock_until(std::chrono::steady_clock::now() + std::chrono::milliseconds(1000)) 等价, 都是等待1s.

    std::recursive_timed_mutex 类

    std::recursive_timed_mutex 在 std::recursive_mutex 的基础上, 让锁支持超时.
    用法同 std::timed_mutex, 超时原理同 std::recursive_mutex.

    std::lock_guard 类型模板

    std::lock_guard 类型模板为基础锁包装所有权. 指定的互斥量在构造函数中上锁, 在析构函数中解锁.
    这就为互斥量锁部分代码提供了一个简单的方式: 当程序运行完成时, 阻塞解除, 互斥量解锁(无论是执行到最后, 还是通过控制流语句break或return, 亦或是抛出异常).
    std::lock_guard 不支持拷贝构造, 拷贝赋值和移动构造.

    std::unique_lock 类型模板

    std::unique_lock 类型模板比 std::loc_guard 提供了更通用的所有权包装器.
    std::unique_lock 可以调用 unlock 释放锁, 而后当再次需要对共享数据进行访问时再调用 lock(), 但是必须注意一次 lock 对应一次 unlock, 不能连续多次调用同一个 lock 或 unlock.
    std::unique_lock 不支持拷贝构造和拷贝赋值, 但是支持移动构造和移动赋值.
    std::unique_lock 比 std::loc_guard 还增加了另外几种构造方式:
    unique_lock(_Mutex& _Mtx, adopt_lock_t) 构建持有锁实例, 其不会调用 lock 或 try_lock, 但析构时默认会调用 unlock.
    unique_lock(_Mutex& _Mtx, defer_lock_t) 构建非持有锁实例, 其不会调用 lock 或 try_lock, 如果没有使用 std::lock 等函数修改标志, 析构时也不会调用 unlock.
    unique_lock(_Mutex& _Mtx, try_to_lock_t) 尝试从互斥量上获取锁, 通过调用 try_lock
    unique_lock(_Mutex& _Mtx, const chrono::duration<_Rep, _Period>& _Rel_time) 在给定时间长度内尝试获取锁
    unique_lock(_Mutex& _Mtx, const chrono::time_point<_Clock, _Duration>& _Abs_time) 在给定时间点内尝试获取锁
    bool owns_lock() const 检查是否拥有一个互斥量上的锁

    std::lock 函数模板

    std::lock 函数模板提供同时锁住多个互斥量的功能, 且不会有因改变锁的一致性而导致的死锁. 其声明如下:
    template<typename LockableType1,typename... LockableType2> void lock(LockableType1& m1,LockableType2& m2...);

  • 相关阅读:
    亿级 Web 系统的容错性建设实践
    Spring 4支持的Java 8新特性一览
    Java多线程干货系列—(一)Java多线程基础
    Sublime Text 2 实用快捷键(Mac OS X)
    spring-事务管理
    100 个 Linux 常用命令大全
    这些年MAC下我常用的那些快捷键
    Java 容器源码分析之HashMap多线程并发问题分析
    MySQL索引结构--由 B-/B+树看
    Java 容器之 Connection栈队列及一些常用
  • 原文地址:https://www.cnblogs.com/gnivor/p/9490167.html
Copyright © 2011-2022 走看看