Подтвердить что ты не робот

Как я могу использовать что-то вроде std::vector <std:: mutex>?

У меня есть большое, но потенциально изменяющееся количество объектов, которые одновременно записываются. Я хочу защитить этот доступ с помощью мьютексов. С этой целью я решил использовать std::vector<std::mutex>, но это не сработает, поскольку std::mutex не имеет конструктора копирования или перемещения, а std::vector::resize() требует этого.

Какое рекомендуемое решение этой головоломки?

изменить: Все контейнеры с произвольным доступом С++ требуют копирования или перемещения конструкторов для повторной калибровки? Будет ли помощь std:: deque?

снова отредактировать

Во-первых, спасибо за все ваши мысли. Меня не интересуют решения, которые позволяют избежать мутации и/или перемещать их в объекты (я воздержусь от подробностей/причин). Поэтому, учитывая проблему, что я хочу регулируемое количество мутаций (там, где настройка гарантирована, когда нет блокировки мьютекса), тогда, как представляется, существует несколько решений.

1 Я мог бы использовать фиксированное количество мутаций и использовать хеш-функцию для сопоставления объектов с мутациями (как в ответе капитана Обливского). Это приведет к коллизиям, но количество столкновений должно быть небольшим, если число муттирований намного больше числа потоков, но все же меньше числа объектов.

2 Я мог бы определить класс-оболочку (как в ответе ComicSansMS), например

struct mutex_wrapper : std::mutex
{
  mutex_wrapper() = default;
  mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {}
  bool operator==(mutex_wrapper const&other) noexcept { return this==&other; }
};

и используйте std::vector<mutex_wrapper>.

3 Я мог бы использовать std::unique_ptr<std::mutex> для управления отдельными мьютексами (как в ответе Маттиаса). Проблема с этим подходом заключается в том, что каждый мьютекс индивидуально распределяется и де-распределяется в куче. Поэтому я предпочитаю

4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );

когда изначально назначается определенное число n_mutex муттиз. Если этого числа позже будет найдено недостаточно, я просто

if(need_mutex > n_mutex) {
  mutices.reset( new std::mutex[need_mutex] );
  n_mutex = need_mutex;
}

Итак, какой из них (1,2,4) я должен использовать?

4b9b3361

Ответ 1

vector требует, чтобы значения были подвижными, чтобы поддерживать непрерывный массив значений по мере его роста. Вы можете создать вектор, содержащий мьютексы, но вы не могли бы сделать ничего, что может потребоваться для его изменения.

В других контейнерах этого требования нет; либо deque или [forward_]list должны работать, если вы строите мьютексы на месте либо во время построения, либо с помощью emplace() или resize(). Такие функции, как insert() и push_back(), не будут работать.

В качестве альтернативы вы можете добавить дополнительный уровень косвенности и сохранить unique_ptr; но ваш комментарий в другом ответе указывает, что вы считаете, что дополнительные затраты на динамическое распределение неприемлемы.

Ответ 2

Вы можете использовать std::unique_ptr<std::mutex> вместо std::mutex. unique_ptr являются подвижными.

Ответ 3

Если вы хотите создать определенную длину:

std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);

mutexes.swap(list);

Ответ 4

Я предлагаю использовать фиксированный пул мьютексов. Сохраните фиксированный массив std::mutex и выберите, какой из них заблокировать, на основе адреса объекта, как вы могли бы сделать с хеш-таблицей.

std::array<std::mutex, 32> mutexes;

std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];

m.lock();

Функция hashof может быть чем-то простым, что сдвигает значение указателя на несколько бит. Таким образом, вам нужно только инициализировать мьютексы один раз, и вы избегаете копии изменения размера вектора.

Ответ 5

Если эффективность является такой проблемой, я предполагаю, что у вас очень маленькие структуры данных, которые меняются очень часто. Тогда лучше использовать Atomic Compare And Swap (и другие атомные операции) вместо использования мьютексов, в частности std::atomic_compare_exchange_strong