gpt4 book ai didi

c++11 - 将互斥体存储在向量/双端队列中 C++

转载 作者:行者123 更新时间:2023-12-03 17:06:42 25 4
gpt4 key购买 nike

我想在一个容器中存储可变数量的互斥锁,比如 vector 或 deque。

在其中一个用例中,我需要可靠且无死锁地锁定所有互斥锁。我还希望有异常安全保证,如果抛出异常,所有互斥锁就好像没有发生锁定一样。

我正在尝试执行以下操作:

std::vector<std::mutex> locks_(n);
std::vector<std::lock_guard<std::mutex> > guards(n);
for(int i = 0; i < n; i++) {
std::lock_guard<std::mutex> guard(locks_[i]);
guards.emplace_back(std::move(guard));
}

但它没有编译,给我:

/usr/include/c++/4.8/ext/new_allocator.h:120:4: error: use of deleted function ‘std::lock_guard<_Mutex>::lock_guard(const std::lock_guard<_Mutex>&) [with _Mutex = std::mutex]’



我想当 lock_guards 被销毁时也可能有问题,因为与构造相比,顺序必须颠倒,但标准为我们节省了:

The delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted. In the case of an array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see 12.6.2).



这种方法是否有任何潜在的缺陷,如何使其发挥作用?

编辑

实际上我错了,似乎 vector 并不能保证特定的破坏顺序。看到这个问题: Order of destruction of elements of an std::vector

编辑2

:如果用例是:

所有互斥锁都由不同的线程以任何顺序锁定/解锁(但是这些线程中的每一个一次仅使用 1 个互斥锁),
但在某些时候,我需要在另一个线程中以安全的方式锁定所有互斥锁。

最佳答案

n 上有一个坚定而低的上限你可以合理地做这样的事情:

#include <iostream>
#include <mutex>
#include <vector>

int
main()
{
constexpr unsigned n_max = 5;
unsigned n;
std::cout << "Enter n: ";
std::cin >> n;
if (std::cin.fail())
throw "oops";
if (n > n_max)
throw "oops";
std::vector<std::mutex> mutexes(n);
std::vector<std::unique_lock<std::mutex>> locks;
for (auto& m : mutexes)
locks.emplace_back(m, std::defer_lock);
switch (locks.size())
{
case 0:
break;
case 1:
locks.front().lock();
break;
case 2:
std::lock(locks[0], locks[1]);
break;
case 3:
std::lock(locks[0], locks[1], locks[2]);
break;
case 4:
std::lock(locks[0], locks[1], locks[2], locks[3]);
break;
case 5:
std::lock(locks[0], locks[1], locks[2], locks[3], locks[4]);
break;
default:
throw "oops";
}
}

它不是那么漂亮。但它很容易推理,因此是可靠的。

笔记:
  • 您需要使用 std::lock(m1, m2, ...)可靠地锁定多个 mutex ,或者重新发明一个算法,比如 std::lock以避免死锁。一种这样的替代算法是,如果你能保证每个人总是锁定 mutexes 中的互斥锁。以相同的顺序(例如按索引),那么您不需要 std::lock总之,只需循环并锁定它们。
  • lock_guard放入 vector 有问题一次一个,如 vector<T>::emplace_back需要 T可移动施工。这就是为什么unique_lock的原因之一在这里工作和 lock_guard没有。 mutexes因为它构造了 vector,所以不会持有不可移动的互斥锁。所有一次,而不是用 emplace_back 添加到它.
  • 在这个例子中 locks保存对 mutexes 的引用.确保在这两个容器之间没有生命周期问题( mutexes 必须比 locks 生命周期长)。
  • 如果您需要在序列末尾添加不可移动的项目,请切换到 deque ,这将适用于 vector惯于。
  • 解锁顺序无所谓,不用担心。只有当不同的线程可能以不同的顺序锁定时,锁定顺序才重要。如果所有线程总是以相同的顺序锁定,请不要担心。但是如果所有线程总是以相同的顺序锁定,请考虑用单个互斥锁替换 n 个互斥锁,因为这听起来等效。
  • 上面的代码假设不同的线程可能以不同的顺序锁定,也许是 mutexes 的一个子集。 .显然它不会扩展到大 n .

  • 编辑 2 在这个问题中,我相信这段代码是可行的。它将可靠地与不同的线程锁定一起工作 mutexes以不同的顺序。每个线程应该形成自己的 locks 本地副本并通过 switch 发送.如果某个线程由于某种原因需要它的 locks成为 mutexes 的子集,或者以不同的顺序构建它,没问题。这就是该解决方案的设计目的。

    插头

    如果你对 std::lock 背后的算法感兴趣,这里是它的各种潜在实现的性能测试,包括您可以在自己的平台上运行的测试代码:

    Dining Philosophers Rebooted

    如果你发现你的执行 std::lock是次优的,请与您的实现者谈谈。 :-)

    关于c++11 - 将互斥体存储在向量/双端队列中 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30418814/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com