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);
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Я могу создать файл и через программный код записывать в него строки с тегами каждый раз, когда это понадобитсяНо, если в Qt существует какая-нибудь...
Почему оператор lock () предназначен для приема только параметров ссылочного типа?
Делаю игру по англоязычному туториалу, все "скопировал" правильно, но что-то не работаетhttps://pixelnest
Использую WPF, MVVM паттернНа ряду с использованием метода Webclient