Как правильно использовать атомарный тип с помощью condition_variable, чтобы избежать блокировки при расслабленном атомарном чтении - PullRequest
0 голосов
/ 22 апреля 2019

В случае общего счетчика, который является ожидаемым (с условием_вариабельной переменной), мне интересно, что лучше всего в отношении счетчика получения между использованием атомарного типа для счетчика (mt_counter_B impl) или блокировкой (mt_counter_A impl)?Кроме того, правильно ли я использовал memory_orders?Я намерен использовать count_relaxed () для пользовательского интерфейса без сохранения состояния, поэтому мне не нужно, чтобы он был безопасным для заказа.

class mt_counter_A
{
protected:
    std::condition_variable cv;
    std::mutex cv_m;
    uint64_t cnt;

public:
    mt_counter_A& operator++() {
        {
            std::lock_guard<std::mutex> lk(cv_m);
            ++cnt;
        }
        cv.notify_all();
    }

    uint64_t count() {
        std::lock_guard<std::mutex> lk(cv_m);
        return cnt;
    }

    void wait_until(uint64_t count) {
        std::unique_lock<std::mutex> lk(cv_m);
        cv.wait(lk, [&] { return cnt >= count; });
    }
};

class mt_counter_B
{
protected:
    std::condition_variable cv;
    std::mutex cv_m;
    std::atomic_uint_fast64_t cnt;

public:
    mt_counter_B& operator++() {
        {
            std::lock_guard<std::mutex> lk(cv_m);
            cnt.fetch_add(std::memory_order_relaxed);
        }
        cv.notify_all();
    }

    uint64_t count(std::memory_order order = std::memory_order_seq_cst) {
        return cnt.load(order);
    }

    uint64_t count_relaxed() {
        return cnt.load(std::memory_order_relaxed);
    }

    void wait_until(uint64_t count) {
        std::unique_lock<std::mutex> lk(cv_m);
        cv.wait(lk, [&]{ return cnt.load(std::memory_order_relaxed) >= count; });
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...