Может ли с ++ мьютекс пересекать метод / переменную? Если так, то почему это не работает здесь? - PullRequest
0 голосов
/ 01 июля 2018

Я пишу программу провайдер-потребитель. Существует много очередей сообщений, и я хочу убедиться, что каждое сообщение, помещенное в очередь в каждой очереди сообщений, имеет последовательный, увеличивающийся индекс, например, <0, "msga">, <1, "msgb">, .... Порядок остается внутри каждой очереди, и разные очереди не имеют значения.

Для этого я использую 2 карты хешей и 2 блокировки мьютекса (я хочу использовать только одну блокировку, но не удалось).

(i) Первая хэш-карта отображает имя очереди на пару <int, mutex *>, в которой int означает счетчик каждой очереди, мьютекс защищает очередь в параллельных запросах. Определение

using umap_cnt = unordered_map<string, pair<int, mutex* > >;
umap_cnt counters;

(ii) Вторая карта хэша отображает имя очереди на фактическое сообщение <int, MSG> (MSG на самом деле строка), определение

using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
umap_msg messages`;

Моя логика

  • найти мьютекс очереди в counters, заблокировать () это
  • используйте counter_iter-> first в качестве индекса сообщения, поместите () его в messages
  • увеличение индекса
  • unlock () блокировка мьютекса

Пример кода выглядит следующим образом

/* File A.cpp */
using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
mutex mtx;
umap_msg messages;
void put(string kname, MSG msg, int index) {
    // If not using mtx here, the message would be out of order.
    // lock_guard<mutex> mtx;
    messages[kname].push_back(make_pair<index, msg>);
}

// Many threads runs producer()
/* File B.cpp*/
using umap_cnt = unordered_map<string, pair<int, mutex* > >
void producer(string kname, MSG msg) {
    umap_cnt::iterator iter = counters.find(kname);
    if (iter == counters.end())
        return;
    // lock the queue
    iter->second.second->lock();
    put(kname, msg, iter->second.first);
    ++iter->second.first; // increase the counter
    iter->second.second->unlock();
}

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

Моя первоначальная цель - использовать только один замок в производителе. Каждая очередь имеет свой собственный мьютекс, и никакие два потока не могут получить блокировку очереди одновременно, поэтому каждое сообщение в каждой очереди должно быть упорядочено. Однако результат оказался не таким, как я ожидал.

Зачем нужна дополнительная блокировка в строке 7? Если мне нужно использовать 2 блокировки, могу ли я оптимизировать их, потому что 2 блокировки кажутся немного тяжелыми?

1 Ответ

0 голосов
/ 01 июля 2018

Я предполагаю, что unordered_map с именем messages начинается пустым (кстати, я правильно понял или код не показывает эту часть?), Затем в строке 8:

messages[kname].push_back(make_pair<index, msg>);

мы пишем messages, используя оператор [] , который выполняет вставку, если ключ еще не существует.

И запись одновременно на unordered_map не поддерживается (см. этот вопрос ), поэтому для обеспечения последовательной записи требуется мьютекс.

...