【发布时间】:2015-01-28 04:59:51
【问题描述】:
我有一个名为 ServerConnectionHandler 的类,它创建了一个用于从服务器读取数据的 boost 线程。 boost 线程绑定到 ServerConnectionHandler 对象。相关代码如下:
ServerConnectionHandler::~ServerConnectionHandler()
{
close();
}
void ServerConnectionHandler::close()
{
closesocket(m_ConnectSocket);
WSACleanup();
}
void ServerConnectionHandler::MsgLoop()
{
int size_recv = 0;
char chunk[DEFAULT_BUFLEN];
while(1)
{
memset(chunk, 0, DEFAULT_BUFLEN);
size_recv = recv(m_ConnectSocket, chunk, DEFAULT_BUFLEN, 0);
if(size_recv > 0)
{
for( int i=0; i < size_recv; ++i )
{
if(chunk[i] == '\n')
{
m_tcpEventHandler.OnClientMessage(m_RecBuffer);
m_RecBuffer.clear();
}
else
{
m_RecBuffer.append(1, chunk[i]);
}
}
}
else if(size_recv == 0)
{
close();
const std::string error = "MsgReceiver Received 0 bytes because connection was closed. MsgReceiver shutting down.\n";
m_tcpEventHandler.OnClientSocketError(error);
break;
}
else
{
char error [512];
sprintf(error, "Error on Receiving Socket. Recv=[%d], WSAError=[%d]. MsgReceiver shutting down.\n", size_recv, WSAGetLastError());
m_tcpEventHandler.OnClientSocketError(error);
close();
break;
}
}
// NOTE: This will eventually call the destructor of ServerConnectionHandler...
m_tcpEventHandler.OnClientDisconnect("Disconnected. Reason: Remote host snapped connection.");
}
我的问题是,当在析构函数中调用 close() 时,接收线程仍在运行并在尝试调用任何 m_tcpEventHandler.OnClient...() 方法时崩溃,因为对象已在此销毁点。
我需要能够在 3 种不同的情况下干净地处理这个问题:
- 当用户手动断开客户端时(在这种情况下会调用析构函数)。
- 当客户端与服务器断开连接时(例如可能因为服务器崩溃)。
- 当应用程序关闭时(需要彻底断开所有连接 - 类似于 #1)。
目前,此代码仅适用于案例 #2。我不想通过任何锁定来减慢接收器线程的速度,因为性能至关重要。根据我的阅读,我看到人们创建了一个 volatile bool 标志,告诉接收线程停止。我用这种方法看到的问题是,如果它在调用析构函数时正在处理消息(m_tcpEventHandler.OnClientMessage())怎么办?然后它可以立即命中被破坏对象的代码(m_tcpEventHandler 可以反过来使用 ServerConnectionHandler 的成员变量或方法)。我想不出一个干净的方法来处理所有 3 个案例。
【问题讨论】:
-
在你的析构函数中等待线程退出。
标签: c++ multithreading sockets boost