繁体   English   中英

Effective Modern C++ 书中 ThreadRAII 的实现是否正确?

[英]Is the implementation of ThreadRAII correct in the Effective Modern C++ book?

书中的第 37 项说明了 ThreadRAII 的实现,它可以加入线程或在线程被销毁时将其分离。 通过声明析构函数,编译器不会生成移动操作,但在书中,作者说没有理由不能移动它们,并说编译器会生成正确的移动操作,并建议我们使用 '= default ' 执行。

#include <thread>

class ThreadRAII
{
public:
    enum class DtorAction { join, detach };

    ThreadRAII(std::thread&& t, DtorAction a)
        : action(a)
        , t(std:: move(t))
    {}

    ~ThreadRAII()
    {
        if(t.joinable())
        {
            if(action == DtorAction::join)
                t.join();
            else
                t.detach();
        }
    }

    ThreadRAII(ThreadRAII&&) = default;

    ThreadRAII& operator=(ThreadRAII&&) = default;

    std::thread& get() { return t; }

private:
    DtorAction action;
    std::thread t;
};

int main()
{
    ThreadRAII t{std::thread{[]{}}, ThreadRAII::DtorAction::join};

    t = ThreadRAII{std::thread{[]{}}, ThreadRAII::DtorAction::detach};

    return 0;
}

但在上面的例子中,std::terminate 被调用了。

我认为默认的移动构造函数应该没问题,但移动赋值不行,因为移动赋值必须在获取新资源之前释放当前资源。 否则,分配将破坏可连接的线程,从而导致程序终止。

我没有在本书的勘误表中看到这个问题。 这本书说默认的移动赋值运算符应该没问题真的错了吗? 我想确定并让其他人查看它以便与作者联系。

这就是我认为应该是的:

#include <thread>

class ThreadRAII
{
public:
    enum class DtorAction { join, detach };

    ThreadRAII(std::thread&& t, DtorAction a)
        : action(a)
        , t(std:: move(t))
    {}

    ~ThreadRAII()
    {
        release();
    }

    ThreadRAII(ThreadRAII&&) = default;

    ThreadRAII& operator=(ThreadRAII&& rhs)
    {
        release();
        action = rhs.action; 
        t = std::move(rhs.t);
        return *this;
    }

    std::thread& get() { return t; }

    void release()
    {
        if(t.joinable())
        {
            if(action == DtorAction::join)
                t.join();
            else
                t.detach();
        }
    }

private:
    DtorAction action;
    std::thread t;
};

int main()
{
    ThreadRAII t{std::thread{[]{}}, ThreadRAII::DtorAction::join};

    t = ThreadRAII{std::thread{[]{}}, ThreadRAII::DtorAction::detach};

    return 0;
}

是的,这是违反 3(5) 的明确规则。

一旦你有一个自定义的 dtor,你必须让你的特殊赋值和构造函数同样自定义。 在这里,销毁的线程导致连接或分离而分配给不连接的事实相对不一致。

作者大概想过assigning-to-empty的情况,算出来也还好,没想到assigning-to-engaged。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM