微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 RAII 套接字类传递给线程

如何解决将 RAII 套接字类传递给线程

我正在制作一个 HTTP 服务器,我想将一个套接字客户端类传递给线程来处理请求。问题是在启动线程后立即调用析构函数,因此套接字被关闭代码的简化版本如下所示。

while (true) {
    Tcpsocket client = m_socket.accept();
    std::thread clientThread([this,&client] { this->handleClient(client); });
    clientThread.detach();
}

我尝试制作一个接受连接并将其传递给具有给定函数的线程的函数,但我无法让它工作。我在这里使用元组是因为您can't pass a parameter pack to lambda in c++17

template<typename Function,typename ...Args>
std::thread TcpListener::acceptAndPasstoThread(Function&& function,Args&&... args)
{
    int socketDescriptor = accept(m_socketDescriptor,nullptr,nullptr);

    std::tuple arguments = std::make_tuple(std::forward<Args>(args)...);

    std::thread clientThread([socketDescriptor,function,arguments] {
        Tcpsocket client = Tcpsocket(socketDescriptor);

        auto callArguments = std::tuple_cat(std::make_tuple(client),arguments);
        std::apply(function,callArguments);

    });

    return clientThread;
}

我可以做这样的事情,但我不想在类之外使用套接字描述符。

while (true)
{
    int clientDescriptor = m_socket.acceptDescriptor();

    std::thread clientThread([this,clientDescriptor] {
        Tcpsocket client = Tcpsocket::fromDescriptor(clientDescriptor);
        this->handleClient(client);
    });

    clientThread.detach();
}

还有什么是使用类成员函数调用 TcpListener::acceptAndPasstoThread 函数的正确方法

解决方法

您的 RAII 班级 TcpSocket 真的应该移动,因为复制在逻辑上是错误的。当然,您可以像 std::shared_ptr 一样实现它,但是值语义有点误导。那么,将其称为反映其共享性质的东西可能会更好。

要使类只移动,您删除复制构造函数复制赋值运算符并提供移动 两个版本。像这样:

class TcpSocket
{
public:
    // ...

    ~TcpSocket() { this->close(); }

    TcpSocket(int descriptor = -1): descriptor(descriptor) {}
  
    // ban copying  
    TcpSocket(TcpSocket const&) = delete;
    TcpSocket& operator=(TcpSocket const&) = delete;

    // implement move so the moved from object will
    // not close this descriptor    
    TcpSocket(TcpSocket&& other): TcpSocket()
    {
        std::swap(descriptor,other.descriptor);
    }

    // same with move assignment
    // this closes any current descriptor but you may
    // want to throw an exception if this descriptor
    // is currently in use.    
    TcpSocket& operator=(TcpSocket&& other)
    {
        if(&other != this)
            this->close(); // or throw?

        std::swap(descriptor,other.descriptor);

        return *this;
    }

private:
    void close()
    {
        if(descriptor != -1)
            ::close(descriptor);
        descriptor = -1;
    }

    int descriptor = -1;
};

然后移动套接字到线程中:

while (true) {
    TcpSocket client = m_socket.accept();
    std::thread clientThread([this,client = std::move(client)] mutable {
        this->handleClient(std::move(client));
    });

    clientThread.detach(); // looks dangerout?
}
,

如果您可以控制 TcpSocket 类,我建议您通过将 private implementation 成员包装在 shared_ptr(或 {{1 }} 如果你使用得当)。

要解决您当前的问题,您可以使用 unique_ptr 而不是原始类,如下所示:

std::shared_ptr<TcpSocket>

您必须更改函数 while (true) { std::shared_ptr<TcpSocket> client = m_socket.accept(); std::thread clientThread([this,client] { this->handleClient(client); }); clientThread.detach(); } void handleClient(std::shared_ptr<TcpSocket> client) { // ... } 才能返回 m_socket.accept()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?