将 CSocket 传递给 std::thread

Posted

技术标签:

【中文标题】将 CSocket 传递给 std::thread【英文标题】:Passing CSocket to std::thread 【发布时间】:2016-06-03 11:12:29 【问题描述】:

我正在使用CSocket 编写多线程服务器。所以,像往常一样,我有监听服务器套接字,并且需要为每个连接的客户端创建接收套接字。为了提供多个客户端处理,我想为每个客户端创建新的std::threaddetach,然后在线程函数中处理这个客户端。


我正在尝试这样做:

int client_handler(CSocket receiver)

  return 1;


CSocket server;
BOOL created = server.Create(12345);
server.Listen();
while(true)

  CSocket receiver;
  if (server.Accept(receiver))
  
     std::thread handler(client_handler, receiver);
  


...

我在 std::thread 实例化时遇到编译器错误:

error C2664: 'std::tuple<int (__cdecl *)(CSocket),CSocket>::tuple(std::tuple<int (__cdecl *)(CSocket),CSocket> &&)': cannot convert argument 1 from 'int (__cdecl &)(CSocket)' to 'std::allocator_arg_t'

我已阅读 std::thread 文档,但仍然无法理解 - 为什么无法将 СSocket 传递给?

【问题讨论】:

MSDN 对CSocket 的复制可构造性出人意料地保持沉默。可能它只是不可复制的构造? @SergeyA CSocket 派生自 CObject,这确实是不可复制的。最好是Detach,将原始SOCKET 传递给线程,然后将Attach 传递给那里。 @IgorTandetnik,我接受它,它也不能移动? @SergeyA 我没有调查过,但如果是的话我会很惊讶。 如果它真的是不可复制的,你也可以用new声明它并传递一个指向client_handler的指针 【参考方案1】:

问题:

您在线程实例化中使用CSocket 对象,按值传递它。传递给std::thread 的可调用参数应该是可移动或可复制构造的。不幸的是,CSocket 既不能复制也不能移动,这就是你得到错误的原因。

解决方案:

另一种方法是通过引用传递套接字。在这种情况下,您必须用std::ref() 包装它,以避免您的线程收到对副本的引用。但是你不能在这里考虑这个替代方案,因为receiver 是一个具有本地存储的对象。它可能在线程完成之前被销毁,导致未定义的行为。

那么有两种可能:

    receiver 成为你的班级成员,或者至少确保它在线程完成之前可用。然后参考方法将变得可行 动态创建 CSocket,使用 shared_ptr 并在线程实例化(和 client_handler())中传递此 shared_ptr

评论:

虽然与您当前的问题没有严格相关,但请注意,在您的 sn-p 中,您将 handler 创建为 if-bloc 的本地对象。因此,当您离开集团且未加入线程时,该对象将被销毁。这会导致UB:你必须在销毁相应的线程对象之前加入或分离线程。

因此,您要么更改代码结构以考虑此约束并管理自己的线程,要么考虑使用std::async(),以防您只想异步执行接收代码。

【讨论】:

以上是关于将 CSocket 传递给 std::thread的主要内容,如果未能解决你的问题,请参考以下文章

std::thread 通过引用传递调用复制构造函数

std::thread 按引用传递调用复制构造函数

混合 C++11 std::thread 和 C 系统线程(即 pthreads)

thread库,附带程序介绍

std::thread 通过引用传递向量元素

在 C++11 中通过引用 std::thread 传递对象