“mutex”和“lock”的区别是什么?

29
我对锁(lock)和互斥体(mutex)之间的区别非常困惑。在Boost文档中,它说: 锁类型
  • 类模板lock_guard
  • 类模板unique_lock
  • 类模板shared_lock
  • 类模板upgrade_lock
  • 类模板upgrade_to_unique_lock
  • 特定于互斥体的类scoped_try_lock
互斥体类型
  • 类mutex
  • typedef try_mutex
  • 类timed_mutex
  • 类recursive_mutex
  • typedef recursive_try_mutex
  • 类recursive_timed_mutex
  • 类shared_mutex
在另一篇文章中,我看到了像这样的函数:
boost::shared_mutex _access;
void reader()
{
  boost::shared_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access
}    
void conditional_writer()
{
  boost::upgrade_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access

  if (something) {
    boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
    // do work here, but now you have exclusive access
  }
  // do more work here, without anyone having exclusive access
}

问题更新

  1. 请问有人能够解释一下 "mutex" 和 "lock" 的区别吗?
  2. 在使用 shared_mutex 时,是否需要创建一个 shared_lock?如果我为 shared_mutex 创建了一个 unique_lock 会发生什么?
  3. 如果我为 mutex 创建了一个 shared_lock,是否意味着该互斥量不能在多个线程之间共享?

你可能也会发现我的文章“互斥锁是如何工作的?”很有帮助:http://mortoray.wordpress.com/2011/12/16/how-does-a-mutex-work-what-does-it-cost/ - edA-qa mort-ora-y
1
这些是新问题。您应该在新问题中提出它们。您不应该在已有的问题中添加跟进。此外,这些内容都在Boost的文档中。 - Nicol Bolas
3个回答

53

互斥锁是一种同步对象。在代码段的开头获取互斥锁并在结束时释放它,以确保没有其他线程同时访问相同的数据。互斥锁通常具有与其所保护的数据相同的生命周期,并且多个线程访问一个互斥锁。

锁对象是封装锁的对象。当对象被构建时,它会获取互斥锁。当它被销毁时,锁被释放。通常为每次访问共享数据创建新的锁对象。


10
锁的生命周期是独占访问代码段的持续时间;互斥锁的生命周期通常是可以被锁定的代码段的存在期。 - Neil G

24

互斥锁是一种可被锁定的对象。锁是维护锁定状态的对象。要创建锁,您需要传递一个互斥锁。


1

锁可以提供互斥,但不能提供条件同步。与信号量不同,锁具有所有者,所有权在锁的行为中起着重要作用。

示例 -

class lockableObject { public void F() {
mutex.lock(); ...; mutex.unlock();
}
public void G() {
mutex.lock(); ...; F(); ...; mutex.unlock();
}
private mutexLock mutex; }
// method G() calls method F()

在lockableObject类中,锁mutex用于将方法F()和G()转换为临界区。因此,在lockableObject的方法内部一次只能有一个线程执行。当线程调用方法G()时,mutex被锁定。当方法G()调用方法F()时,在F()中执行mutex.lock(),但是调用线程不会被阻塞,因为它已经拥有mutex。如果mutex是二元信号量而不是锁,则在F()中执行mutex.P()时,从G()到F()的调用将阻塞调用线程。(回想一下,二元信号量上的P()和V()操作的完成必须交替进行。)这将创建死锁,因为没有其他线程能够在F()或G()内部执行。

锁和二元信号量之间的差异如下: 1 对于二元信号量,如果两个调用在没有任何中间调用V()的情况下调用P(),则第二个调用将被阻塞。但是,拥有锁并再次请求所有权的线程不会被阻塞。(请注意,锁并不总是递归的,因此在使用锁之前请检查文档。) 2 连续调用lock()和unlock()的所有者必须是同一个线程。但是,可以由不同的线程连续调用P()和V()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接