程序运行两天两夜,出现了假死现象,高手请进

jjiaming 软件部经理  2005-08-28 10:19:44
RT,运行两天两夜后,发现程序响应很慢,但是还没有挂掉,而且发现这期间数据库里的内容也发生了改变,说明程序还在运行。小弟只好把程序检查一遍,程序中没有费时的操作和计算,只有主进程有一个WaitForSingleObject(),于是怀疑是这里导致的。现将相关代码贴出:

volatile bool bStop;//线程终止标志
volatile CEvent eventEnd;//发送结束事件
volatile SENDINFO SendInfo;//待发送数据的结构体
volatile CEvent eventSend;//有数据要发送事件

//发送线程
DWORD WINAPI SendThread(LPVOID DataPoint)
{
CMainCtrl* MainCtrl = (CMainCtrl*) DataPoint;
CServerTunnel* ServerTunnel = &(MainCtrl->m_tServerTunnel);
while(!bStop)
{
if(::WaitForSingleObject(eventSend.m_hObject,2000) != WAIT_OBJECT_0)
continue;//检测是否有数据要发送
if(MainCtrl->pBuf == NULL)
{
ResetEvent(eventSend.m_hObject);
SetEvent(eventEnd.m_hObject);
continue;
}
long a= ServerTunnel->net_Send(SendInfo.hSocket,SendInfo.wMessageID,
MainCtrl->pBuf,SendInfo.BufLen);

if(a != SendInfo.BufLen + MESSAGE_HEADER_LEN)
TRACE("注意,发送的字节数不对,发送数%d ,待发送数%d\n",a,SendInfo.BufLen);
ResetEvent(eventSend.m_hObject);
SetEvent(eventEnd.m_hObject);
}
return 1;
}
//发送数据的函数
unsigned long CMainCtrl::net_Send(SOCKET hSocket,DWORD wMessageID, char* pSendBuf ,int length)
{
Sleep(15);
     if(::WaitForSingleObject(eventEnd.m_hObject,2000) != WAIT_OBJECT_0)
{//发送超时
bStop = false;
TRACE("发送超时!!");
TerminateThread(ThreadHandle,0);//杀死超时线程
ThreadHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendThread,(LPVOID*)this,0,&ThreadId); //新建发送线程
TRACE("创建了一个新的线程");
}

     ResetEvent(eventEnd.m_hObject);
SendInfo.m_tServerTunnel = &m_tServerTunnel;
SendInfo.hSocket = hSocket;
SendInfo.wMessageID = wMessageID;
if(pBuf != NULL)
delete[] pBuf;
pBuf = new char[length];
memcpy((void*)pBuf,pSendBuf,length);
SendInfo.BufLen = length;
SetEvent(eventSend.m_hObject);//有数据要发送
return 1;
}

程序以前偶尔过发送超时的问题,所以WaitForSingleObject堵塞的机会不大,时间也比较短,但是如果发生多个发送连续超时,这样WaitForSingleObject就会使主线程严重堵塞(但程序还能运行),不知小弟这样分析对不对,然后请大家看一下这两段代码有什么不对的地方,如果确实是这里出了问题,那出现多个发送连续超时的原因又是什么呢?小弟敬候高手的到来
...全文
366 点赞 收藏 16
写回复
16 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
liuwei200000 2005-08-30
线程SendThread一直处于运行状态,是为有一个无限循环while(!bStop),当bstop = true时,线程就会跳出循环而结束(这是一个最好的结束线成的方法)
回复
liuwei200000 2005-08-29
几点建议:
1,在发送数据函数里最好不要用WaitForSingleObject(eventEnd.m_hObject,2000) != WAIT_OBJECT_0),最好另起用一个线程监测该事件,然后做处理,不然会影响数据的发送效果,;
2,线程的启用,停止也不要放在net_Send函数里处理;
3,不知道你的程序具体实现一个什么样的功能,个人认为你的程序设计逻辑不太理想,建议看看线程创建和终止线程 ,及事件的相关处理(线程的同步讲的有);
回复
jjiaming 2005-08-29
大家还是没明白我的意思,我是说在线程中的这一句:
long a= ServerTunnel->net_Send(SendInfo.hSocket,SendInfo.wMessageID,
MainCtrl->pBuf,SendInfo.BufLen);
有时会发生“阻塞”(我不知道这样表达对不对),也就是说当程序执行到这里的时候,偶尔就不往下执行,就一直停在这里,所以没有办法指望线程自动退出,只能用野蛮的办法强行让它退出。至于为什么它不往下执行,我也很想知道,另外有没有比较完美的强行关闭线程的方法
回复
csnew 2005-08-29
TerminateThread(ThreadHandle,0);//杀死超时线程
会有内存泄漏,
WaitForSingleObject应该这样用:
1:创建一个退出的事件(全局变量)
CEvent g_eventExit;
2.
while(!bStop)
{
......................
if(::WaitForSingleObject(g_eventExit, 0) == WAIT_OBJECT_0)
{
bStop = TRUE;
break;
}
..................
}

3.在你想终止循环的地方调用g_eventExit.SetEvent();
回复
yll1986 2005-08-28
回复
jjiaming 2005-08-28
自己先顶一下
回复
33184777 2005-08-28
up
回复
jjiaming 2005-08-28
现将修改后的代码贴出:

volatile bool bStop;//线程终止标志
volatile CEvent eventEnd;//发送结束事件
volatile SENDINFO SendInfo;//待发送数据的结构体
volatile CEvent eventSend;//有数据要发送事件

//发送线程
DWORD WINAPI SendThread(LPVOID DataPoint)
{
CMainCtrl* MainCtrl = (CMainCtrl*) DataPoint;
CServerTunnel* ServerTunnel = &(MainCtrl->m_tServerTunnel);
while(!bStop)
{
if(::WaitForSingleObject(eventSend.m_hObject,2000) != WAIT_OBJECT_0)
continue;//检测是否有数据要发送
ResetEvent(eventEnd.m_hObject);
if(MainCtrl->pBuf == NULL)
{
ResetEvent(eventSend.m_hObject);
SetEvent(eventEnd.m_hObject);
continue;
}
long a= ServerTunnel->net_Send(SendInfo.hSocket,SendInfo.wMessageID,
MainCtrl->pBuf,SendInfo.BufLen);

if(a != SendInfo.BufLen + MESSAGE_HEADER_LEN)
TRACE("注意,发送的字节数不对,发送数%d ,待发送数%d\n",a,SendInfo.BufLen);
ResetEvent(eventSend.m_hObject);
SetEvent(eventEnd.m_hObject);
}
return 1;
}
//发送数据的函数
unsigned long CMainCtrl::net_Send(SOCKET hSocket,DWORD wMessageID, char* pSendBuf ,int length)
{
Sleep(15);
     if(::WaitForSingleObject(eventEnd.m_hObject,2000) != WAIT_OBJECT_0)
{//发送超时
bStop = false;
TRACE("发送超时!!");
TerminateThread(ThreadHandle,0);//杀死超时线程
ThreadHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendThread,(LPVOID*)this,0,&ThreadId); //新建发送线程
TRACE("创建了一个新的线程");
}

     SetEvent(eventEnd.m_hObject);
SendInfo.m_tServerTunnel = &m_tServerTunnel;
SendInfo.hSocket = hSocket;
SendInfo.wMessageID = wMessageID;
if(pBuf != NULL)
delete[] pBuf;
pBuf = new char[length];
memcpy((void*)pBuf,pSendBuf,length);
SendInfo.BufLen = length;
SetEvent(eventSend.m_hObject);//有数据要发送
return 1;
}

回复
jjiaming 2005-08-28

谢谢楼上的星星。小弟初学多线程,而且又涉及到头疼的线程同步,哎。
对于楼上提到的第一个问题,小弟对于你的回答看不大懂。
     if(::WaitForSingleObject(eventEnd.m_hObject,2000) != WAIT_OBJECT_0)
{//发送超时
bStop = false;
TRACE("发送超时!!");
TerminateThread(ThreadHandle,0);//杀死超时线程
ThreadHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendThread,(LPVOID*)this,0,&ThreadId); //新建发送线程
TRACE("创建了一个新的线程");
}
这一段代码是在发送之前检测上一次发送是否超时,是每一次发送都会检测的,而不是“只对第一次产生发生数据的时候可以很好的作理”。

对于第二个问题,我想了一下,我把net_Send函数中的ResetEvent(eventEnd.m_hObject);函数改为SetEvent,然后再在发送线程的
if(::WaitForSingleObject(eventSend.m_hObject,2000) != WAIT_OBJECT_0)
continue;//检测是否有数据要发送
语句后加上ResetEvent(eventEnd.m_hObject);是不是有可以解决这个问题了?
回复
lianglp 2005-08-28
初步看了下你上面的代码,问题比较多:
1.如果发生多个发送连续超时,这样WaitForSingleObject就会使主线程严重堵塞
------------------------------------------------------------------------
肯定会产生这个问题,因为你现在只对第一次产生发生数据的时候可以很好的作
出处理,如这时连续两次或以上,如发送函数没有处理完毕,第二次的数据很有
可能不会发送出去了。
2.如发生时net_send等待起时,调用TerminateThread()不是很好的解决方法,
这个函数用在进程退出时,如先需要退出工作线程,再退出主线程的时候才可以
用这个方法结束工作线程,否则,会产生资源不能及时回收的情况,这个当发生
多次这种情况时,系统连接调用CreateThread()都会失败。

其实最主要的原因还是楼主没有作好线程同步的问题。
回复
teli_eurydice 2005-08-28
up
回复
jjiaming 2005-08-28
大家有所不知,以前就因为发送超时,不,准确的说是发送函数根本无法返回,导致程序非正常地挂起,当时根本没用线程,也当然没有WaitForSingleObject了,我感觉很奇怪,为什么发送函数不能返回,但奇怪归奇怪,问题还是得解决啊,于是只好利用线程可以被强行杀死的特点,把发送部分做成了线程.
to younggle(洋溢):为什么要Sleep呢,我觉得问题好像不在这
回复
younggle 2005-08-28
if(::WaitForSingleObject(eventSend.m_hObject,2000) != WAIT_OBJECT_0)
{
Sleep(50); //增加这句话就可以了

continue;//检测是否有数据要发送
}

还有在程序退出的时候也使用 WaitForSingleObject 等待该线程地正常退出。
回复
oyljerry 2005-08-28
程序响应很慢,是否有内存泄漏等,检查一下
回复
oyljerry 2005-08-28
TerminateThread(ThreadHandle,0);//杀死超时线程
最好用消息等来让线程自己退出
回复
MagicYang1225 2005-08-28
up
回复
发帖
网络编程
创建于2007-09-28

1.8w+

社区成员

VC/MFC 网络编程
申请成为版主
帖子事件
创建了帖子
2005-08-28 10:19
社区公告
暂无公告