C ++ синхронизированный класс (многопоточность) - PullRequest
0 голосов
/ 18 октября 2019

Предположим следующий минимальный пример:

#include <iostream>
#include <mutex>
#include <thread>

template<class Parent>
class Synchronized final {
public:
    friend Parent;

    explicit Synchronized(Parent &parent) : m_parent(parent), m_lock(parent.m_mutex) {}

    Synchronized(Synchronized&&) = default;

    Parent* operator->() noexcept {
        return &m_parent;
    }

private:
    Synchronized(const Synchronized&) = delete;
    Synchronized& operator=(const Synchronized&) = delete;
    Synchronized& operator=(Synchronized&&) = delete;

    Parent &m_parent;
    std::unique_lock<std::mutex> m_lock;
};

template<class T>
class Synchronizeable {
public:
    virtual ~Synchronizeable() = default;

    Synchronized<T> synchronized() {
        return Synchronized<T>(static_cast<T>(*this));
    }

private:
    friend class Synchronized<T>;

    std::mutex m_mutex;
};

class Counter : public Synchronizeable<Counter> {
public:
    Counter() {}

    int m_val = 0;
};

int main(int argc, char **argv) {
    Counter cnt;

    std::thread inc([&]() {
        Synchronized<Counter> sync(cnt);
        for (int i = 0; i < 10; i++) {
            sync->m_val++;
            std::cout << "INC, new val=" << cnt.m_val << std::endl;
        }
    });

    std::thread dec([&]() {
        Synchronized<Counter> sync(cnt);
        for (int i = 0; i < 10; i++) {
            sync->m_val--;
            std::cout << "DEC, new val=" << cnt.m_val << std::endl;
        }
    });

    inc.join();
    dec.join();

    return 0;
}

Конструкция выглядит следующим образом. Класс реализует интерфейс «Synchronizeable», поэтому он наследует мьютекс и метод класса synchronized (). Это также делает класс «Синхронизированный» другом затронутого класса, поэтому мьютекс может использоваться в его конструкторе.

Экземпляр оболочки «Синхронизированный» может быть построен вокруг любого объекта, который реализует / наследует «Синхронизируемый»"interface.

Каковы проблемы (дизайна) с моими синхронизированными классами? Для меня это выглядит так, как будто эта реализация работала правильно, но также выглядит довольно просто, и я не нашел много решений для достижения объекта типа «Монитор / Синхронизированный» в стиле Java в C ++. Я не совсем уверен, что я делаю достаточно здесь (возможно, что-то упускаю).

(незначительная) проблема стиля заключается в том, что дочерний класс всегда должен наследоваться от интерфейса "Synchronizeable", то есть всегдадолжен передать свое собственное имя класса в качестве параметра шаблона. Я не нашел способа обойти это до сих пор.

...