Поточно-безопасно ли объявлять член класса std :: future как изменяемый? - PullRequest
4 голосов
/ 24 сентября 2019

Безопасно ли (поточно-ориентированное) объявление std::future как mutable, поскольку его функция get() меняет свое состояние.Я предполагаю, что это похоже на std::mutex, что безопасно сделать mutable.

template <typename T>
struct S {
    void query() {
        m_fut = doAsyncQuery();
    }

    template <typename L>
    void get(L lambda) const {
        lambda(m_f.get());
    }

    mutable std::future<T> m_f;
};

1 Ответ

2 голосов
/ 24 сентября 2019

это потокобезопасно?

Нет, но это не имеет значения.

std::future предназначено для использования в одном потоке и не являетсяпоточно-ориентированный дизайн.Нет смысла делить его между несколькими потоками.Вы должны вызвать get() только один раз, а затем выбросить его.

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

(Конечно, вы можете передавать право собственности на std ::uture из одного потока в другой. Но в любой момент времени должен удерживаться только один потоки используйте std :: future.)

Может ли оно быть изменяемым?

Да.Фактически, std::future не может быть const, так как его состояние изменяется по определению, когда присоединенная операция завершается и когда вы вызываете get().

Однако mutable не должно быть ключевым словом, которое нужно искать здесь.Конечно, вы можете обернуть std::future в class или struct ключевым словом mutable, а затем создать const экземпляр этого класса, но вы скрываете важную часть информации (а именно, что вашаобертка совсем не const). (Это может иметь смысл в более сложном классе, но я бы сказал, что сложный класс с членом std :: future является признаком плохого дизайна.)

Вместо этого вы должны сделатьтакой класс-оболочка или структура также неконстантные:

template <typename T>
struct S {
    void query() {
        m_fut = doAsyncQuery();
    }

    template <typename L>
    void get(L lambda) {    // remove const here
        lambda(m_f.get());
    }

    std::future<T> m_f;     // remove mutable here
};

Пока вы знаете, что экземпляры S не должны быть константными, вы можете вызывать get только один раз, и этовы не должны делиться S между потоками, вы должны быть в безопасности.

...