C++11 的 lock_guard 和 unique_lock 的简单使用

    在 C++1x 之后,我们编写多线程可以直接使用标准库里的函数,不必根据平台的不同使用 posix_thread 之类的库了,这样就实现了跨平台的编程。

一、std::lock_guard 的介绍

    std::lock_guard 的原型是一个模板类,定义如下:

template<class Mutex> class lock_guard;

    lock_guard 通常用来管理一个 std::mutex 类型的对象,通过定义一个 lock_guard 一个对象来管理 std::mutex 的上锁和解锁。在 lock_guard 初始化的时候进行上锁,然后在 lock_guard 析构的时候进行解锁。这样避免了我们对 std::mutex 的上锁和解锁的管理。注意,lock_guard 并不管理 std::mutex 对象的声明周期,也就是说在使用 lock_guard 的过程中,如果 std::mutex 的对象被释放了,那么在 lock_guard 析构的时候进行解锁就会出现空指针错误之类。

下面是一个使用例子:

//
// Created by 陈国威 on 2018/6/21.
//

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

std::mutex mtx;
using std::cout;
using std::endl;

void print_event(int x)
{
  if (x % 2 == 0)
    {
      cout << x << "is event" << endl;
    }
  else
    {
      throw(std::logic_error("not event"));
    }
}

void print_id(int id)
{
  try
    {
      std::lock_guard<std::mutex> lck(mtx);
      print_event (id);
    }
  catch(std::logic_error&)
    {
      cout << "[exception caught]\n";
    }

}

int main()
{
  std::thread threads[10];
  for (int i = 0; i < 10; ++i)
    {
      threads[i] = std::thread(print_id, i+1);
    }

  for (auto &th : threads)
    {
      th.join ();
    }


  return 0;
}


二、std::unique_lock 的介绍

    unique_lock 和 lock_guard 一样,对 std::mutex 类型的互斥量的上锁和解锁进行管理,一样也不管理 std::mutex 类型的互斥量的声明周期。但是它的使用更加的灵活,支持的构造函数如下:

default (1)
unique_lock() noexcept;
locking (2)
explicit unique_lock(mutex_type& m);
try-locking (3)
unique_lock(mutex_type& m, try_to_lock_t tag);
deferred (4)
unique_lock(mutex_type& m, defer_lock_t tag) noexcept;
adopting (5)
unique_lock(mutex_type& m, adopt_lock_t tag);
locking for (6)
template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep,Period>& rel_time);
locking until (7)
template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);
copy [deleted] (8)
unique_lock(const unique_lock&) = delete;
move (9)
unique_lock(unique_lock&& x);
(1) 默认构造函数 新创建的 unique_lock 对象不管理任何 Mutex 对象。
(2) locking 初始化

新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。 (3) try-locking 初始化 新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。 (4) deferred 初始化 新创建的 unique_lock 对象管理 Mutex 对象 m,但是在初始化的时候并不锁住 Mutex 对象。 m 应该是一个没有当前线程锁住的 Mutex 对象。 (5) adopting 初始化 新创建的 unique_lock 对象管理 Mutex 对象 m, m 应该是一个已经被当前线程锁住的 Mutex 对象。(并且当前新创建的 unique_lock 对象拥有对锁(Lock)的所有权)。 (6) locking 一段时间(duration) 新创建的 unique_lock 对象管理 Mutex 对象 m,并试图通过调用 m.try_lock_for(rel_time) 来锁住 Mutex 对象一段时间(rel_time)。 (7) locking 直到某个时间点(time point) 新创建的 unique_lock 对象管理 Mutex 对象m,并试图通过调用 m.try_lock_until(abs_time) 来在某个时间点(abs_time)之前锁住 Mutex 对象。 (8) 拷贝构造 [被禁用] unique_lock 对象不能被拷贝构造。 (9) 移动(move)构造

    新创建的 unique_lock 对象获得了由 x 所管理的 Mutex 对象的所有权(包括当前 Mutex 的状态)。调用 move 构     造之后, x 对象如同通过默认构造函数所创建的,就不再管理任何 Mutex 对象了。

三、总结

扫描二维码关注公众号,回复: 2288035 查看本文章

    如果我们只是简单地使用互斥量的话,首选 lock_guard就可以了。如果要对 互斥量添加一些限制条件啥的,那么使用 unique_lock 更加地灵活。



猜你喜欢

转载自blog.csdn.net/gochenguowei/article/details/80767120
今日推荐