4

Is it safe (thread-safe) to declare a std::future as being mutable since its get() function changes its state. I assume that it's like std::mutex which is safe to be made 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;
};
4

1 回答 1

2

它是线程安全的吗?

不,但这没关系。

std::future旨在用于单个线程,并且在设计上不是线程安全的。在多个线程之间共享它是没有意义的。您应该get()只调用一次然后将其丢弃。

(运行附加操作并设置返回值的线程在get()这里不相关。实现为您管理和隐藏必要的同步。)

(当然,您可以将 std::future 的所有权从一个线程转移到另一个线程。但在任何给定时间,只有一个线程应该持有并使用 std::future。)

它可以是可变的吗?

是的。事实上,std::future不可能,const因为它的状态根据定义在附加操作完成和您调用get().

但是mutable不应该是在这里寻找的关键字。当然,您可以将 a 包装std::future在 aclassstruct使用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不能是 const,你只能调用get一次,并且你不应该S在线程之间共享一个,你就应该是安全的。

于 2019-09-23T22:54:15.330 回答