一个IOCP莫名崩溃的问题,求高手指教

孟如庭 2014-09-15 02:30:17
最近在学习IOCP,根据<<Windows Sockets网络开发----基于Visual C++实现>>自己实现了一个iocp
服务线程和通信函数如下。

现在的问题是,并发量大的时候会崩溃,简单的10/100个没问题。我自己写了测试工具,12k个线程同时和server端通信,有时候会崩溃,崩溃的详细情况见ProcessClientIO函数。我试验过几次,有时候12k线程也正常。

求教高手指教,哪里有问题


这个是服务线程
DWORD WINAPI ServiceThread( void *pParam )
{
CMyService *pService = (CMyService*)pParam;//主窗口指针
HANDLE hComPort = pService->m_hCompPort;//完成端口

CClientSocketContext * pClient;

DWORD dwIoSize; //传输字节数

LPOVERLAPPED lpOverlapped; //重叠结构指针
BOOL bFlagExit = FALSE; //服务线程退出
BOOL bIORet;

CClientListManager * pClientMgr;

pClientMgr=CClientListManager::GetClientListManager();

pService->DebugMsg("pClientMgr %lx In ServiceThread ",pClientMgr);
while (!bFlagExit)
{
dwIoSize = -1;
lpOverlapped = NULL;

pClient = NULL;

//等待I/O操作结果
bIORet = GetQueuedCompletionStatus(hComPort,
&dwIoSize,
(LPDWORD) &pClient,
&lpOverlapped,
INFINITE);


if (FALSE == bIORet )
{
pService->DebugMsg("CardService: failed overlapped operation occurs. maybe client timeout");
}
//成功的操作完成
if(bIORet && lpOverlapped && pClient)
{
pService->DebugMsg("CardService: normal overlapped occurs,lpOverlapped %lx,pClient %lx",lpOverlapped,pClient);

pClientMgr->ProcessClientIO(pClient, lpOverlapped, dwIoSize);
}
//服务器退出
if(!pService->m_bTcpipServerRunning)
{
pService->DebugMsg("CardService: exit.(m_bTcpipServerRunning FALSE)");
bFlagExit = TRUE;
}


}

return 0;
}


这个是处理IO数据函数,崩溃的时候是在这里
void CClientListManager::ProcessClientIO( CClientSocketContext* pClient, 
LPOVERLAPPED pOverlapped,
DWORD dwIOSize)
{
if (0==dwIOSize)
{
//close client
DeleteClient(pClient);
return;
}

//崩溃的时候,从一次调试可以看到,这里dwIOSize的值是正确的。pOverlapped、pClient、pIO的值都是非法的,所以下面进行判断的时候崩溃了。奇怪的是这里pOverlapped和pClient都是GetQueuedCompletionStatus获得的
PIO_OPERATION_DATA pIO = CONTAINING_RECORD(pOverlapped, IO_OPERATION_DATA,overlapped
if (pIO->type==OP_WRITE)
{
pClient->AsyncRecvData();
//具体其他操作
}
else if (pIO->type==OP_READ)
{
//其他操作
}
}


读写操作

BOOL CClientSocketContext::AsyncRecvData( void )
{
DWORD flags = 0; //标志
DWORD recvBytes =0; //发送字节数

ZeroMemory(&m_iIO, sizeof(m_iIO));
m_iIO.type = OP_READ;//操作类型

WSABUF wsaBuf;
wsaBuf.buf = (char*)&m_iIO.recvBuf; //
wsaBuf.len = sizeof(m_iIO.recvBuf);

time(&m_tLastTimeValue);

//读取数据
if (WSARecv(m_socket,
&wsaBuf,
1,
&recvBytes,
&flags,
&m_iIO.overlapped,
NULL) == SOCKET_ERROR)
{
if(ERROR_IO_PENDING != WSAGetLastError())
{
return FALSE;
}
}
return TRUE;
}



BOOL CClientSocketContext::AsyncSendData( void )
{
DWORD flags = 0; //标志
DWORD sendBytes =0; //发送字节数

m_oIO.type = OP_WRITE; //操作类型


WSABUF wsaBuf;
wsaBuf.buf = (char*)&(m_oIO.recvBuf); //
wsaBuf.len = m_oIO.ulDataLen;

time(&m_tLastTimeValue);

//发送数据
if (WSASend(m_socket,
&wsaBuf,
1,
&sendBytes,
flags,
&m_oIO.overlapped,
NULL) == SOCKET_ERROR)
{
if(ERROR_IO_PENDING != WSAGetLastError())//成功发起重叠操作
{
return FALSE;
}
}
return TRUE;
}

...全文
745 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
孟如庭 2014-10-17
  • 打赏
  • 举报
回复
引用 29 楼 xian_wwq 的回复:
[quote=引用 28 楼 feiyue1206 的回复:] [quote=引用 24 楼 xian_wwq 的回复:] [quote=引用 23 楼 feiyue1206 的回复:] [quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了[/quote] 超时处理和异常关闭socket归并为同一套处理逻辑比较好 如果超时,不直接处理client list 通过调用PostQueuedCompletionStatus,在IOCP的工作线程中 关闭socket,清理资源 [/quote] 最近调试这个程序,发现post是没问题。发现一个奇怪的问题 超时post时,GetQueuedCompletionStatus会返回两次,而客户端关闭socket,GetQueuedCompletionStatus只会返回一次。 这种现象正常吗? [/quote] 后一种情况正常,前一个不正常。有一点没有搞明白,什么叫超时post?[/quote] 是这样的。client超时后,PostQueuedCompletionStatus特定的数据。GetQueuedCompletionStatus会得到相应的内容,处理过程,和客户端关闭socket逻辑一样。进行清理工作,close socket之类的,然后又会得到一个GetQueuedCompletionStatus,而且返回的是FALSE.
孟如庭 2014-10-16
  • 打赏
  • 举报
回复
引用 24 楼 xian_wwq 的回复:
[quote=引用 23 楼 feiyue1206 的回复:] [quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了[/quote] 超时处理和异常关闭socket归并为同一套处理逻辑比较好 如果超时,不直接处理client list 通过调用PostQueuedCompletionStatus,在IOCP的工作线程中 关闭socket,清理资源 [/quote] 最近调试这个程序,发现post是没问题。发现一个奇怪的问题 超时post时,GetQueuedCompletionStatus会返回两次,而客户端关闭socket,GetQueuedCompletionStatus只会返回一次。 这种现象正常吗?
xian_wwq 2014-10-16
  • 打赏
  • 举报
回复
引用 28 楼 feiyue1206 的回复:
[quote=引用 24 楼 xian_wwq 的回复:] [quote=引用 23 楼 feiyue1206 的回复:] [quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了[/quote] 超时处理和异常关闭socket归并为同一套处理逻辑比较好 如果超时,不直接处理client list 通过调用PostQueuedCompletionStatus,在IOCP的工作线程中 关闭socket,清理资源 [/quote] 最近调试这个程序,发现post是没问题。发现一个奇怪的问题 超时post时,GetQueuedCompletionStatus会返回两次,而客户端关闭socket,GetQueuedCompletionStatus只会返回一次。 这种现象正常吗? [/quote] 后一种情况正常,前一个不正常。有一点没有搞明白,什么叫超时post?
孟如庭 2014-09-17
  • 打赏
  • 举报
回复
引用 25 楼 my3439955 的回复:
[quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
是个问题,解决方案: 方案一:引用计数法,使用加计数,销毁减计数,计数为零才真正销毁 方案二:销毁前CancelIo [/quote] 感觉这两个方法和我说的问题都无关。。。加减计数,如果工作线程具体使用前,超时线程减到0,销毁了,不是一样有问题。
孟如庭 2014-09-17
  • 打赏
  • 举报
回复
引用 24 楼 xian_wwq 的回复:
[quote=引用 23 楼 feiyue1206 的回复:] [quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了[/quote] 超时处理和异常关闭socket归并为同一套处理逻辑比较好 如果超时,不直接处理client list 通过调用PostQueuedCompletionStatus,在IOCP的工作线程中 关闭socket,清理资源 [/quote] 谢谢,豁然开朗,感觉这个方法可以。让我想想具体怎么实现。
  • 打赏
  • 举报
回复
引用 19 楼 feiyue1206 的回复:
我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
是个问题,解决方案: 方案一:引用计数法,使用加计数,销毁减计数,计数为零才真正销毁 方案二:销毁前CancelIo
xian_wwq 2014-09-17
  • 打赏
  • 举报
回复
引用 23 楼 feiyue1206 的回复:
[quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了[/quote] 超时处理和异常关闭socket归并为同一套处理逻辑比较好 如果超时,不直接处理client list 通过调用PostQueuedCompletionStatus,在IOCP的工作线程中 关闭socket,清理资源
孟如庭 2014-09-16
  • 打赏
  • 举报
回复
@my3439955 帮我看下19楼的情况
引用 18 楼 my3439955 的回复:
[quote=引用 17 楼 feiyue1206 的回复:] [quote=引用 13 楼 my3439955 的回复:] CompletionKey最好使用固定的值,不要试图利用它存储一个指针,lpOverlapped中完全可以存储任何用户数据。GetQueuedCompletionStatus之后先要判断CompletionKey是否正确,正确后才进行后续的处理。
固定值,倒是一个思路。也等我实验一下 我想传过来CClientSocketContext指针的话,只能在类的成员变量IO_OPERATION_DATA结构中,添加一个指向当前类实例的指针? 额外问一句,GetQueuedCompletionStatus有可能传过来错误的CompletionKey?这个是什么原因 [/quote] 按理说不会出现错误的CompletionKey。我在我的实现中总是先按照CompletionKey来判断,因为有不止一个CompletionKey,所以做一个switch case,不正常的CompletionKey自然被忽略了。所以我没见过错误的CompletionKey。 所有的数据如socket 缓冲区等都可以用overlapped来处理,无需动用CompletionKey[/quote]
孟如庭 2014-09-16
  • 打赏
  • 举报
回复
我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
孟如庭 2014-09-16
  • 打赏
  • 举报
回复
引用 19 楼 feiyue1206 的回复:
我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
感觉这个问题无解了,servicethrd中GetQueuedCompletionStatus返回后,加锁前,如果tiemeout线程删掉了这个client,还是有问题。改怎么处理呢?想不清楚了
孟如庭 2014-09-16
  • 打赏
  • 举报
回复
引用 21 楼 xian_wwq 的回复:
[quote=引用 19 楼 feiyue1206 的回复:] 我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
具体得看对Client list加锁是怎么加的? 多线程对公用变量的所有操作按道理都应该加锁[/quote] 使用的是list。加锁就加了对list的增删操作,超时如下,但是在ServiceThrd没加。我在想是不是要每个client都加个锁,不是只对list加锁。不过我没想清楚怎么在timeout中对每一个加锁
DWORD CClientListManager::KillClientOfTimeout()
{
	EnterCriticalSection(&m_critical_section_for_client_list);
	list<CClientSocketContext*>::iterator iterList;;
	CClientSocketContext* pFindClient;
	time_t tCurTime;
	double dTimediff; 
	for (iterList = m_ClientList.begin(); iterList!=m_ClientList.end();)
	{ 
		time(&tCurTime);
		//dTimediff=tCurTime-(*iterList)->m_tLastTimeValue;
		dTimediff=difftime(tCurTime,(*iterList)->m_tLastTimeValue);  
		if(dTimediff>s_m_dCardTimeoutValue)
		{
			pFindClient=*iterList;    

			iterList=m_ClientList.erase(iterList);
			delete pFindClient;//删的过程对改client加个锁?
		}
		else
		{
			iterList++;
		}
	}
	LeaveCriticalSection(&m_critical_section_for_client_list);
	return 0;
}
xian_wwq 2014-09-16
  • 打赏
  • 举报
回复
引用 19 楼 feiyue1206 的回复:
我在逻辑上发现一个错误。 两个线程,一个timeout 删除超市的client,一个是服务线程ServiceThrd(不止一个,不过可以当做一个看) 有io发生,进入ServiceThrd,GetQueuedCompletionStatus返回 pclient指针,如果现在timeout线程,正好把这个client删除了,这时ProcessClientIO中的pclient指针就是非法的了,就会出现问题。可是怎么解决这个问题呢?我没思路了 现在加锁都是对整个client list的,timeout中这么加了,在ServiceThrd中有 GetQueuedCompletionStatus返回就要加锁?
具体得看对Client list加锁是怎么加的? 多线程对公用变量的所有操作按道理都应该加锁
  • 打赏
  • 举报
回复
引用 17 楼 feiyue1206 的回复:
[quote=引用 13 楼 my3439955 的回复:] CompletionKey最好使用固定的值,不要试图利用它存储一个指针,lpOverlapped中完全可以存储任何用户数据。GetQueuedCompletionStatus之后先要判断CompletionKey是否正确,正确后才进行后续的处理。
固定值,倒是一个思路。也等我实验一下 我想传过来CClientSocketContext指针的话,只能在类的成员变量IO_OPERATION_DATA结构中,添加一个指向当前类实例的指针? 额外问一句,GetQueuedCompletionStatus有可能传过来错误的CompletionKey?这个是什么原因 [/quote] 按理说不会出现错误的CompletionKey。我在我的实现中总是先按照CompletionKey来判断,因为有不止一个CompletionKey,所以做一个switch case,不正常的CompletionKey自然被忽略了。所以我没见过错误的CompletionKey。 所有的数据如socket 缓冲区等都可以用overlapped来处理,无需动用CompletionKey
孟如庭 2014-09-15
  • 打赏
  • 举报
回复
引用 13 楼 my3439955 的回复:
CompletionKey最好使用固定的值,不要试图利用它存储一个指针,lpOverlapped中完全可以存储任何用户数据。GetQueuedCompletionStatus之后先要判断CompletionKey是否正确,正确后才进行后续的处理。
固定值,倒是一个思路。也等我实验一下 我想传过来CClientSocketContext指针的话,只能在类的成员变量IO_OPERATION_DATA结构中,添加一个指向当前类实例的指针? 额外问一句,GetQueuedCompletionStatus有可能传过来错误的CompletionKey?这个是什么原因
孟如庭 2014-09-15
  • 打赏
  • 举报
回复
引用 14 楼 Idle_ 的回复:
[quote=引用 12 楼 feiyue1206 的回复:] [quote=引用 11 楼 Idle_ 的回复:] [quote=引用 9 楼 feiyue1206 的回复:] [quote=引用 8 楼 Idle_ 的回复:] 12k个线程? 你不会是在一台机器上进行测试的吧? 即要运行服务器又要运行有12k个线程的客户端, 很难想象不崩溃的可能性(小到忽略不计?)。
是在一台机器上。这个有关系吗,除了电脑会很卡很卡[/quote] 当然有关系,而且关系很大。 默认一个线程需要占用1M内存作为堆栈,12k个线程就近12G(只是堆栈哦), 一个tcp socket需要8k缓冲区,client 12k+server 12k=24k个socket需要近200M系统缓冲区(这是不可交换内存,即一直占用的是机器物理内存),既然你使用的是iocp, 那么用的肯定是overlapped IO,不算你发送/接收所占用的用户内存,即使OVERLAPPED结构占用的内存就不少,也不说12k个IO完成时通知的中断内核来不来得及处理,光进行IO完成->IOCP队列添加/减少+IOCP线程池管理在内核中的负担就不可想象了, 再加上运行时线程切换需要进行的磁盘/内存交换,中间只要有那么一两次读写出错,那么结果必然是系统崩溃。[/quote] 好高端。学习了。 那我是应该用两个电脑实验了?[/quote] 如果你的目的不是测试系统到底能够处理多少线程的话,那么客户端不要用多线程,哪怕用单线程循环12k个非阻塞socket光发送不检查错误都比你现在这个测试模型好。 [/quote] 好的。我修改测试工具在实验下
SiGoYi 2014-09-15
  • 打赏
  • 举报
回复
楼主可以看一下windows核发心编程。上面说了,对于一个进程来说它所能开启的线程数量是有限制的,这个数量是可以计算得出来。windows系统为一个进程分配2G的用户内存,而一个线程需要1M的内存,所以理论上说一个进程能开启最大的线程数为:2G/1M这么多个,当然实际情况要少得多。 如果楼主的程序真的要求启动的线程比较多,那么为楼主提供一个解决的办法。 1、多进程交互;(可以式式) 2、记得win核上说可以修改进程的用户内存,但好像最大能扩大到3G。
阿呆_ 2014-09-15
  • 打赏
  • 举报
回复
引用 12 楼 feiyue1206 的回复:
[quote=引用 11 楼 Idle_ 的回复:] [quote=引用 9 楼 feiyue1206 的回复:] [quote=引用 8 楼 Idle_ 的回复:] 12k个线程? 你不会是在一台机器上进行测试的吧? 即要运行服务器又要运行有12k个线程的客户端, 很难想象不崩溃的可能性(小到忽略不计?)。
是在一台机器上。这个有关系吗,除了电脑会很卡很卡[/quote] 当然有关系,而且关系很大。 默认一个线程需要占用1M内存作为堆栈,12k个线程就近12G(只是堆栈哦), 一个tcp socket需要8k缓冲区,client 12k+server 12k=24k个socket需要近200M系统缓冲区(这是不可交换内存,即一直占用的是机器物理内存),既然你使用的是iocp, 那么用的肯定是overlapped IO,不算你发送/接收所占用的用户内存,即使OVERLAPPED结构占用的内存就不少,也不说12k个IO完成时通知的中断内核来不来得及处理,光进行IO完成->IOCP队列添加/减少+IOCP线程池管理在内核中的负担就不可想象了, 再加上运行时线程切换需要进行的磁盘/内存交换,中间只要有那么一两次读写出错,那么结果必然是系统崩溃。[/quote] 好高端。学习了。 那我是应该用两个电脑实验了?[/quote] 如果你的目的不是测试系统到底能够处理多少线程的话,那么客户端不要用多线程,哪怕用单线程循环12k个非阻塞socket光发送不检查错误都比你现在这个测试模型好。
  • 打赏
  • 举报
回复
CompletionKey最好使用固定的值,不要试图利用它存储一个指针,lpOverlapped中完全可以存储任何用户数据。GetQueuedCompletionStatus之后先要判断CompletionKey是否正确,正确后才进行后续的处理。
孟如庭 2014-09-15
  • 打赏
  • 举报
回复
引用 11 楼 Idle_ 的回复:
[quote=引用 9 楼 feiyue1206 的回复:] [quote=引用 8 楼 Idle_ 的回复:] 12k个线程? 你不会是在一台机器上进行测试的吧? 即要运行服务器又要运行有12k个线程的客户端, 很难想象不崩溃的可能性(小到忽略不计?)。
是在一台机器上。这个有关系吗,除了电脑会很卡很卡[/quote] 当然有关系,而且关系很大。 默认一个线程需要占用1M内存作为堆栈,12k个线程就近12G(只是堆栈哦), 一个tcp socket需要8k缓冲区,client 12k+server 12k=24k个socket需要近200M系统缓冲区(这是不可交换内存,即一直占用的是机器物理内存),既然你使用的是iocp, 那么用的肯定是overlapped IO,不算你发送/接收所占用的用户内存,即使OVERLAPPED结构占用的内存就不少,也不说12k个IO完成时通知的中断内核来不来得及处理,光进行IO完成->IOCP队列添加/减少+IOCP线程池管理在内核中的负担就不可想象了, 再加上运行时线程切换需要进行的磁盘/内存交换,中间只要有那么一两次读写出错,那么结果必然是系统崩溃。[/quote] 好高端。学习了。 那我是应该用两个电脑实验了?
阿呆_ 2014-09-15
  • 打赏
  • 举报
回复
引用 9 楼 feiyue1206 的回复:
[quote=引用 8 楼 Idle_ 的回复:] 12k个线程? 你不会是在一台机器上进行测试的吧? 即要运行服务器又要运行有12k个线程的客户端, 很难想象不崩溃的可能性(小到忽略不计?)。
是在一台机器上。这个有关系吗,除了电脑会很卡很卡[/quote] 当然有关系,而且关系很大。 默认一个线程需要占用1M内存作为堆栈,12k个线程就近12G(只是堆栈哦), 一个tcp socket需要8k缓冲区,client 12k+server 12k=24k个socket需要近200M系统缓冲区(这是不可交换内存,即一直占用的是机器物理内存),既然你使用的是iocp, 那么用的肯定是overlapped IO,不算你发送/接收所占用的用户内存,即使OVERLAPPED结构占用的内存就不少,也不说12k个IO完成时通知的中断内核来不来得及处理,光进行IO完成->IOCP队列添加/减少+IOCP线程池管理在内核中的负担就不可想象了, 再加上运行时线程切换需要进行的磁盘/内存交换,中间只要有那么一两次读写出错,那么结果必然是系统崩溃。
加载更多回复(10)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧