如何解决将 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 举报,一经查实,本站将立刻删除。