I try to implement mutex using multiple condition variables inside, locked flag, global mutex for flag, and global mutexes for condition variables initialization (before initialization they are set to nullptr). I want to implement such mutex as exercise. Following code produces Segmentation fault, how to fix it?
#include <thread>
#include <vector>
#include <cassert>
#include <mutex>
#include <condition_variable>
using mutxCointainer = std::vector<std::shared_ptr<std::mutex>>;
class MutexOfConditions {
public:
MutexOfConditions();
void lock();
void unlock();
private:
const int static howMany = 10;
std::shared_ptr<std::condition_variable> variables[howMany];
unsigned long int counters[howMany];
bool locked;
std::mutex &getLockMutex();
mutxCointainer &getVariablesMutexes();
};
MutexOfConditions::MutexOfConditions() {
for (int i = 0; i < howMany; i++) {
variables[i] = nullptr;
counters[i] = 0;
}
locked = false;
}
mutxCointainer &MutexOfConditions::getVariablesMutexes() {
static mutxCointainer mu;
mu.reserve(howMany);
for (int i = 0; i < howMany; i++) {
mu.emplace_back(std::make_shared<std::mutex>());
}
return mu;
}
std::mutex &MutexOfConditions::getLockMutex() {
static std::mutex mutex;
return mutex;
}
void MutexOfConditions::lock() {
getLockMutex().lock();
if (locked) {
getLockMutex().unlock();
size_t MUT_INDEX = std::hash<std::thread::id>()(std::this_thread::get_id()) % howMany;
getVariablesMutexes()[MUT_INDEX]->lock();
if (variables[MUT_INDEX] == nullptr) {
variables[MUT_INDEX] = std::make_shared<std::condition_variable>();
}
getVariablesMutexes()[MUT_INDEX]->unlock();
std::unique_lock<std::mutex> lk(getLockMutex());
variables[MUT_INDEX]->wait(lk, [this] { return !this->locked; });
locked = true;
} else {
locked = true;
getLockMutex().unlock();
}
}
void MutexOfConditions::unlock() {
getLockMutex().lock();
locked = false;
for (size_t i = 0; i < howMany; i++) {
if (variables[i] != nullptr) {
variables[i]->notify_one();
}
}
getLockMutex().unlock();
}
const size_t THREADS_PER_USAGE = 5;
const int REPEATS = 5;
MutexOfConditions m1, m2, m3, m4, m5, m6, m7, m8;
int result = 0;
void usage1() {
for (int i = 0; i < REPEATS; ++i) {
m1.lock();
m2.lock();
m4.lock();
m5.lock();
m6.lock();
m8.lock();
++result;
m2.unlock();
m4.unlock();
m1.unlock();
m5.unlock();
m6.unlock();
m8.unlock();
}
}
void usage2() {
for (int i = 0; i < REPEATS; ++i) {
m3.lock();
m2.lock();
m4.lock();
m6.lock();
m5.lock();
m7.lock();
m8.lock();
++result;
m3.unlock();
m2.unlock();
m4.unlock();
m6.unlock();
m5.unlock();
m7.unlock();
m8.unlock();
}
}
int main() {
std::vector<std::thread> threads;
threads.reserve(THREADS_PER_USAGE * 2);
for (size_t i = 0; i < THREADS_PER_USAGE; ++i) {
threads.emplace_back(usage1);
threads.emplace_back(usage2);
}
for (auto &thread : threads) {
thread.join();
}
assert(result == 2 * THREADS_PER_USAGE * REPEATS);
}
Aucun commentaire:
Enregistrer un commentaire