移动std :: mutex的构造函数

jco*_*der 37 c++ c++11

c ++标准库中的许多类现在都有移动构造函数,例如 -

thread::thread(thread&& t)
Run Code Online (Sandbox Code Playgroud)

但似乎std :: mutex没有.我知道它们不能被复制,但是能够从"make_mutex"函数中返回一个似乎是有意义的.(不是说它有用,只是它有意义)

有什么理由说std :: mutex没有移动构造函数吗?

seh*_*ehe 40

嗯......主要是因为我认为他们不应该.从字面上看.

在某些操作系统中,互斥锁可能被建模为句柄(因此您可以复制它们)但是IIRC会对pthreads互斥锁进行就地操作.如果要重新定位,那么任何线程安全都会立即飞出窗口(其他线程如何知道互斥锁刚刚改变了它的内存地址......)?

  • 好吧,我想这是有道理的:)我在考虑代表互斥锁的互斥对象,所以你可以把它移动到另一个对象,但如果你认为它是*是*互斥体,那么移动它是没有意义的,你是对, (6认同)
  • @JohnB:你可以用`unique_lock <mutex>`做你想做的事.这是一个可锁定的对象(具有互斥的API),可以移动它.哦,但我不会立刻将它暴露给多个线程.但是你可以在每个线程中有一个引用相同的`mutex`. (6认同)
  • @TED 除非你能保证存储永远不会移动(`std::array&lt;std::mutex, 100&gt;` 是一个容器。`boost::intrusive::slist&lt;std::mutex, ...&gt;` :))。但除此之外,是的。你总是可以**[用`shared_ptr&lt;std::mutex&gt;`](http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/sp_techniques.html#as_lock)**排序。 (2认同)

Luc*_*ton 17

请记住,C++将"不为你不使用的东西付钱"的理念铭记于心.让我们考虑一个假想的平台,它使用opaque类型来表示互斥体; 我们称之为那种类型mutex_t.如果在该互斥锁上操作的接口mutex_t*用作参数,例如像void mutex_init(mutex_t* mutex);"构造"互斥锁一样,那么互斥锁的地址可能就是用于唯一标识互斥锁的情况.如果是这种情况,则表示mutex_t不可复制:

mutex_t kaboom()
{
    mutex_t mutex;
    mutex_init(&mutex);
    return mutex; // disaster
}
Run Code Online (Sandbox Code Playgroud)

这样做时mutex_t mutex = kaboom();,无法保证与功能块中的&mutex值相同&mutex.

当一天实现者想要std::mutex为该平台编写一个实现者时,如果该类型的要求是可移动的,那么这意味着内部mutex_t必须放置在动态分配的内存中,并具有所有相关的惩罚.

在另一方面,虽然现在std::mutex不是可移动的,它很容易从一个函数"回归"之一:返回一个std::unique_ptr<std::mutex>代替.这仍然支付动态分配的成本,但仅在一个地方.所有其他不需要移动的代码都不需要std::mutex付费.

换句话说,因为移动互斥锁不是互斥锁的核心操作,不需要std::mutex移动就不会移除任何功能(由于不可移动 T => 可移动 std::unique_ptr<T>转换)并且将产生最小的开销成本直接使用本机类型.


std::thread可能已被类似地指定为不可移动,这将使得典型的生命周期如下:在调用有价值的构造函数之后运行(与执行的线程相关联); 在调用join或之后,分离/加入(与没有执行的线程相关联)detach.根据我的理解,它std::vector<std::thread>仍然可用,因为类型本来可以EmplaceConstructible.

编辑:不正确!该类型仍然需要移动(毕竟重新分配时).所以对我来说这是不够的理由:这是典型的投入std::thread到像容器std::vectorstd::deque,这样的功能是值得欢迎的那种类型.