1
votes

I have the following array of mutexes:

std::mutex mtx[5];

And I would like to lock them all with an RAII style:

std::lock_guard<std::mutex> grd[5] { mtx[0], mtx[1], mtx[2], mtx[3], mtx[4] };

While the above code works, it isn't ideal as I can't write it independently of the size of the array (here 5).

Is there a way to do that? Shall I work with template magic to create an std::initializer_list out of an array? (is that possible?)

I'm open to using std::array or std::vector instead of C-style arrays, I used those here for conciseness. Ideally this works in C++14 but any solution up to latest standards is fine.

1
Can you clarify in what kind of an application this kind of mutexes are needed, specifically an array of mutexes (you can't have a vector of mutexes, C++ does not work this way)? It seems a bit strange, can you give an example of what kind of locking requirements this approach solves? Maybe there's a better way to do it. Just want to make sure that this isn't some senseless puzzle that comes from one of those many kinds of spam sites that promise to turn anyone into a C++ uberhacker, simply by solving their puzzles (I don't want to waste my time if that's the case). - Sam Varshavchik
I'm a bit curious about which compiler and C++ version you are using. I can't get std::lock_guard<std::mutex> grd[5] { mtx[0], mtx[1], mtx[2], mtx[3], mtx[4] }; to compile in g++, clang++ or MSVC. - Ted Lyngmo

1 Answers

3
votes

What you want is std::scoped_lock. It takes N mutexes and locks them on creation and unlocks on destruction. That would give you

std::scoped_lock sl{mtx[0], mtx[1], mtx[2], mtx[3], mtx[4]};

If that's still too verbose you can wrap that in a factory function like

// 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);
}