【问题标题】:Does std::function lock a mutex when calling an internal mutable lambda?调用内部可变 lambda 时,std::function 是否会锁定互斥锁?
【发布时间】:2014-02-13 22:02:35
【问题描述】:

C++ 标准库对其类型提供以下保证,除非另有说明:

(1) 读取操作(即处理const 对象)是线程安全的。这意味着只要没有线程同时向对象写入(应用非const 操作),多个线程就可以同时从一个对象读取而没有竞争条件。

(2) 多个线程可以同时读取和写入任意对象,只要每个对象一次最多只能被一个线程访问。

标准库需要用户类型的相同保证。 (您可以在GotW #95 中阅读有关这些内容的信息,或观看Herb at C++ and Beyond 2012 对此的解释。)

现在我的问题是,如果下面的结论是正确的:由于std::functionoperator()const 成员函数,所以它必须是线程安全的。如果在构造时传入的仿函数有一个 const operator() 成员函数,那么 std::function 对象可以假定它是线程安全的并且只是转发调用。但是,如果在构造时传递给它的函子有一个可变的operator(),那么这个操作不需要是线程安全的,但std::function 仍然需要,因为调用运算符仍然是 const。因此std::function 必须在外部同步对存储的可变函子的调用,因此使用互斥锁。这意味着在将可变 lambda 传递给 std::function 的构造函数时会产生性能开销。

这个推理正确吗?如果是这样,当前的实现是否兼容?

【问题讨论】:

  • 我不知道 std::function 是否真的获得了一个互斥体,但如果确实获得了,它也不会有太大帮助,因为它无法控制它没有进行的调用。因此,如果它这样做,我会感到惊讶。一般来说,没有办法自动使线程不安全的代码成为线程安全的。如果你希望你的代码是线程安全的,你需要自己处理同步。

标签: c++ c++11 locking mutex functor


【解决方案1】:

Herb 所说的关于标准库对数据竞争安全的保证的行为在 C++11 §17.6.5.9 中指定:

17.6.5.9 避免数据竞争 [res.on.data.races]

1 本节规定了实现应满足的要求以防止数据竞争 (1.10)。除非另有说明,否则每个标准库函数都应满足每个要求。实施可能会在以下未指定的情况下防止数据竞争。

2 C++ 标准库函数不得直接或间接访问可由当前线程以外的线程访问的对象 (1.10),除非这些对象是通过函数的参数直接或间接访问的,包括 this

3 C++ 标准库函数不得直接或间接修改当前线程以外的线程可访问的对象 (1.10),除非通过函数的非 const 参数直接或间接访问对象,包括 this

4 [注意:例如,这意味着实现不能在没有同步的情况下将静态对象用于内部目的,因为即使在没有显式在线程之间共享对象的程序中也可能导致数据竞争。 ——尾注]

5 C++ 标准库函数不得访问通过其参数或通过其容器参数的元素间接访问的对象,除非通过调用其规范对这些容器元素所要求的函数。

6 通过调用标准库容器或字符串成员函数获得的迭代器上的操作可以访问底层容器,但不得修改它。 [注意:特别是,使迭代器无效的容器操作与与该容器关联的迭代器上的操作冲突。 ——尾注]

7 如果对象对用户不可见并且受到保护以防止数据竞争,则实现可以在线程之间共享它们自己的内部对象。

8 除非另有说明,否则 C++ 标准库函数应仅在当前线程内执行所有操作,前提是这些操作具有对用户可见 (1.10) 的效果。

9 [注意:如果没有可见的副作用,这允许实现并行化操作。 ——尾注]

假设您将 lambda 闭包传递给 std::function - 例如通过构造函数或赋值运算符 - 然后调用 functionoperator()。在第 1 段中,operator () 被允许“直接或间接通过函数的参数,包括this”访问闭包对象。在第 2 段中,它可能不会改变 std::function 对象本身或闭包对象的状态,因为它们都是“通过函数的非常量参数直接或间接访问的,包括 this”。这种行为很容易实现,无需任何针对同时线程访问的保护,即锁定。

operator () 然后调用 lambda 闭包的 operator(),并且规则发生变化:您的 lambda 的 operator () 不是标准库函数,因此不受指定标准库函数行为的规则的约束。你可以根据语言规则对闭包对象做任何你想做的事情。

标准库保证不会通过其操作引入任何数据竞争,但您应对您的代码可能引入的任何数据竞争负责。

【讨论】:

  • 我猜 Herb 正在将某些内容解释为标准中未包含的内容:除非另有说明,否则带有 const 参数的函数是线程安全的。或者他不是?我想我会发布一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多