使用 std::lock_guard 数组锁定 std::mutex 数组

Non*_*yme 1 c++ arrays constructor raii

我有以下互斥体数组:

std::mutex mtx[5];
Run Code Online (Sandbox Code Playgroud)

我想用 RAII 风格锁定它们:

std::lock_guard<std::mutex> grd[5] { mtx[0], mtx[1], mtx[2], mtx[3], mtx[4] };
Run Code Online (Sandbox Code Playgroud)

虽然上面的代码可以工作,但它并不理想,因为我无法独立于数组的大小(此处为 5)来编写它。

有没有办法做到这一点?我应该使用模板魔法来创建一个std::initializer_list数组吗?(那可能吗?)

我愿意使用std::arraystd::vector代替 C 风格的数组,为了简洁起见,我在这里使用了这些数组。理想情况下,这适用于 C++14,但任何符合最新标准的解决方案都可以。

Nat*_*ica 6

你想要的是std::scoped_lock。它需要 N 个互斥体并在创建时锁定它们并在销毁时解锁它们。那会给你

std::scoped_lock sl{mtx[0], mtx[1], mtx[2], mtx[3], mtx[4]};
Run Code Online (Sandbox Code Playgroud)

如果这仍然太冗长,您可以将其包装在工厂函数中,例如

// function that actually creates the lock
template<typename Mutexes, std::size_t N, std::size_t... Is>
auto make_scoped_lock(Mutexes (&mutexes)[N], std::index_sequence<Is...>)
{
    return std::scoped_lock{mutexes[Is]...};
}

// helper function so you don't have to create your own index_sequence
template<typename Mutexes, std::size_t N>
auto make_scoped_lock(Mutexes (&mutexes)[N])
{
    return make_scoped_lock(mutexes, std::make_index_sequence<N>{});
}

int main()
{
    std::mutex mtx[5];
    auto lock = make_scoped_lock(mtx);
}
Run Code Online (Sandbox Code Playgroud)

如果您改用 astd::array来保存互斥体,那么代码可以简化为调用来std::apply将数组扩展为参数包,如下所示

template<typename Mutexes>
auto make_scoped_lock(Mutexes& mutexes)
{
    return std::apply([](auto&... mutexes) { return std::scoped_lock{mutexes...}; }, 
                      mutexes);
}

int main()
{
    std::array<std::mutex, 5> mtx;
    auto sl = make_scoped_lock(mtx);
}
Run Code Online (Sandbox Code Playgroud)