C++ 对象和线程
Posted
技术标签:
【中文标题】C++ 对象和线程【英文标题】:C++ objects and threads 【发布时间】:2014-10-30 09:34:52 【问题描述】:我正在做一个简单的服务器应用程序,你可以有多个连接,每个连接都是一个线程。这是我希望它看起来像的示例(它不起作用),有一个线程集合,其中每个线程实例化一个类连接的对象:
class connection;
class server
std::vector<std::thread> active_connections;
public:
void listen() active_connections.push_back(std::thread(connection));
;
我一直在寻找解决方案,但我能找到的最好的是一些成员函数线程。当我测试它时,解决方案变得非常错误,例如:
class connection;
class server
std::vector<std::thread> active_connections;
public:
void new_connection() ...
void listen()
active_connections.push_back(std::thread(&server::new_connection,this));
;
消息是:错误:使用已删除的函数‘std::thread::thread(const std::thread&)。 这是否意味着 std::thread 类想要复制服务器类?我不太懂 C++,所以请不要发火,我只是在问。
谢谢!
编辑:
这就是发生这种情况的地方:
void server::do_listen()
int addr_size = sizeof(sockaddr_in);
sockaddr_in client_sock;
connection_info cn_info;
while(true)
int csock;
if((csock = accept(server_sock, (sockaddr*)&client_sock, (socklen_t*)&addr_size)) != -1)
printf("Incomming connection from %s.\n", inet_ntoa(client_sock.sin_addr));
memset(&cn_info,0, sizeof(connection_info));
cn_info.sock_addr = client_sock;
cn_info.sock = csock;
std::thread thr(&server::new_connection, *this, cn_info);
thr.join();
到目前为止。 server::new_connection()
仍然是空的。
【问题讨论】:
Error C2280: 'std::thread::thread(const std::thread &)' : attempting to reference a deleted function的可能重复 这意味着有东西试图复制一个不可复制的thread
对象。但是您发布的代码并没有这样做,并且一旦我修复了明显的错误就会编译(active_connections
应该是一个变量,而不是一个函数)。请发布一个最小的测试用例来演示您遇到的问题。
【参考方案1】:
问题出在这里:
std::thread thr(&server::new_connection, *this, cn_info);
^
您正在绑定服务器对象的副本;这是不可复制的,因为它包含(一个容器)不可复制的thread
对象。相反,绑定一个指针:
std::thread thr(&server::new_connection, this, cn_info);
有些人可能会发现 lambda 更具可读性;这会按值捕获this
指针和cn_info
:
std::thread thr([=]new_connection(cn_info););
正如评论者所说,您可以通过绑定reference wrapper 来混淆解决方案:
std::thread thr(&server::new_connection, std::ref(*this), cn_info);
但我更愿意尽可能消除而不是增加复杂性。
【讨论】:
+1 但我们还要提一下std::ref
和 std::cref
en.cppreference.com/w/cpp/utility/functional/ref
@Peter:如果你这么说的话。它只是与这个问题的外围相关,在这里不需要,除非你对不必要的复杂性有一种迷恋,但无论如何我已经提到了。【参考方案2】:
这是否意味着 std::thread 类要复制服务器类?
不,这意味着在某处制作了 std::thread
的副本,但这是禁止的,因为 std::thread
在 NonCopyable 中(请注意构造函数列表中的 thread(const thread&) = delete;
)。
您应该删除任何执行thread
副本的代码。您发布的那个不执行此类复制。
在“幕后”制作副本的示例是线程变量向量中的push_back
,即:
std::thread myThread;
myVector.push_back(myThread);
在您的代码中:
active_connections.push_back(std::thread(&server::new_connection,this));
当你推回一个临时的,它不会被复制而是移动到向量中。
【讨论】:
好吧,这个措辞不正确。我的意思是push_back
操作(push_back(std::thread(&server::new_connection,this));
)没有复制。将编辑。【参考方案3】:
向您作者提出更多设计问题:
您为一个连接创建一个线程。如果你有十个连接,你就有十个线程。但是,如果您要处理 10000 个连接,您会怎么做?我不确定你的操作系统是否喜欢这样。
如果您只有 N 个线程来处理您的网络连接,则更好的连接处理方法(仅在我看来)是。如果您的计算机具有例如六个核心,您可以只为网络内容花费一个、两个或更多线程。所以你有一个特定大小的线程池。
前摄器模式对您来说可能很有趣:
http://en.wikipedia.org/wiki/Proactor_pattern
如果您正在寻找可以处理此类事情的库,您可以查看即将推出的名为 Boost.Asynchronous 的 C++ Boost 库:
https://github.com/henry-ch/asynchronous
这个库仍在开发中,但非常好。我已经使用该库制作了一些简单的客户端/服务器应用程序。
【讨论】:
或者他可以使用现有的boost库asio:boost.org/doc/libs/1_56_0/doc/html/boost_asio.html 当然,Boost.Asio 目前可用。但是 Boost.Asio 有一些讨厌的错误。使用 Boost.Asio 编写一个处理多个连接的服务器并不是一件有趣的事情 ;-)以上是关于C++ 对象和线程的主要内容,如果未能解决你的问题,请参考以下文章
线程安全地构造 C++ 对象(MFC CRecordset)