Многопоточность. Проблемы с пониманием mutex и lock_guard

105
22 марта 2021, 18:30

UPD: удалил вторую часть вопроса, оставил чисто мьютекс и лок-гард.

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

Мне нужно создать словарь, разделенный на несколько частей для того, чтоб иметь возможность одновременно получать доступ к разным диапазонам, но не получать одновременного доступа к одному, я выбираю в качестве полей класса вектор словарей и вектор мьютексов. Так же я добавляю в поля класса две переменные, в которых будет храниться размер, на который делится словарь, и размер одной части словаря. Чтоб иметь к ним доступ в любом месте кода.

У меня есть вспомогательная функция, которая переводит из знакового числа в беззнаковое.

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

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

И вот здесь возникает проблема. Судя по результатам теста, секция не лочится.

Собственно, код:

#include "test_runner.h"
#include "profile.h"
#include <algorithm>
#include <future>
#include <limits>
#include <numeric>
#include <vector>
#include <string>
#include <random>
using namespace std;
template <typename T>
size_t Unsign(T position) {
    size_t pos = position - numeric_limits<T>::min();
    return pos;
}
template <typename K, typename V>
void UpdateMap(mutex& mut, map<K, V>& maps, map<K, V>& result) {
    lock_guard<mutex> l(mut);
    result.insert(maps.begin(), maps.end());
}
template <typename K, typename V>
class ConcurrentMap {
public:
  static_assert(is_integral_v<K>, "ConcurrentMap supports only integer keys");
  struct Access {
    V& ref_to_value;
    lock_guard<mutex> l;
  };
  explicit ConcurrentMap(size_t bucket_count) : size_(bucket_count), mutexs(bucket_count), maps(bucket_count) {
      size_of_one = Unsign(numeric_limits<K>::max()) / size_;
  }
  Access operator[](const K& key) {
      size_t position = Unsign(key) / size_of_one;
      return { maps[position][key], lock_guard(mutexs[position]) };
  }
  map<K, V> BuildOrdinaryMap() {
      map<K, V> result;
      vector<future<void>> f;
      for (size_t i = 0; i < maps.size(); i++) {
          f.push_back(async(UpdateMap, ref(mutexs[i]), ref(maps[i]), ref(result)));
      }
      for (auto& i : f) {
          i.get();
      }
      return result;
  }
private:
    size_t size_ = 1;
    size_t size_of_one;
    vector<mutex> mutexs;
    vector<map<K, V>> maps;
};
void RunConcurrentUpdates(
    ConcurrentMap<int, int>& cm, size_t thread_count, int key_count
) {
  auto kernel = [&cm, key_count](int seed) {
    vector<int> updates(key_count);
    iota(begin(updates), end(updates), -key_count / 2);
    shuffle(begin(updates), end(updates), default_random_engine(seed));
    for (int i = 0; i < 2; ++i) {
      for (auto key : updates) {
        cm[key].ref_to_value++;
      }
    }
  };
  vector<future<void>> futures;
  for (size_t i = 0; i < thread_count; ++i) {
    futures.push_back(async(kernel, i));
  }
}
void TestConcurrentUpdate() {
  const size_t thread_count = 3;
  const size_t key_count = 50000;
  ConcurrentMap<int, int> cm(thread_count);
  RunConcurrentUpdates(cm, thread_count, key_count);
  const auto result = cm.BuildOrdinaryMap();
  ASSERT_EQUAL(result.size(), key_count);
  for (auto& [k, v] : result) {
    AssertEqual(v, 6, "Key = " + to_string(k));
  }
}
int main() {
  TestRunner tr;
  RUN_TEST(tr, TestConcurrentUpdate);
}
READ ALSO
Qt. Как сгенерировать HTML-файл с тегами?

Qt. Как сгенерировать HTML-файл с тегами?

Я могу создать файл и через программный код записывать в него строки с тегами каждый раз, когда это понадобитсяНо, если в Qt существует какая-нибудь...

78
оператор lock ()

оператор lock ()

Почему оператор lock () предназначен для приема только параметров ссылочного типа?

104
При запуске игры в Unity не воспроизводится анимация, которую я сделал

При запуске игры в Unity не воспроизводится анимация, которую я сделал

Делаю игру по англоязычному туториалу, все "скопировал" правильно, но что-то не работаетhttps://pixelnest

113
C# Отмена асинхронного метода блокирует изменение полей

C# Отмена асинхронного метода блокирует изменение полей

Использую WPF, MVVM паттернНа ряду с использованием метода Webclient

113