1、我知道可以让线程函数正常结束退出,但是我发现即使是线程函数的正常退出,内存还是会增加。
2、由于socket的发送和接收在线程函数的while(1)中,所以当socket接收阻塞时,采用给线程发送消息,或者setevent等方式,是不能叫醒线程的。只能采用TerminateThread + CloseHandle的方式终止线程,但是这样,内存的增长更快。
线程函数:
UINT ThreadFun(LPVOID lpVoid)
{
CSocketView* pView = (CSocketView*)lpVoid; //CSocketView是我的视图类,会传几个 //标志进来,socket暂停标志,线程结束标志。
CSocket socket; //在线程函数中声明一个临时变量
char buf[255]; //接收数组
int SocketConnectRetryTime = 0; //socket连接主机重试次数,如果大于10次,就报警连接失败。
BOOL m_bConnnected = FALSE; //是否连接上主机的标志,为1表示连接上。
if(!AfxSocketInit()) //初始化SOCKET
{
AfxMessageBox("初始化Socket失败。");
return 0;
}
int i = 0; //i表示重试次数
while(!socket.Create()) //创建socket
{
i ++ ;
if(i > 10)
{
DWORD error = GetLastError();
CString str;
str.Format("创建失败,错误码:%d",error);
AfxMessageBox(str);
return 0;
break;
}
}
i = 0;
while(!socket.Connect("127.0.0.1",20000))//连接主机
{
i ++ ;
if(i > 10)
{
DWORD error = GetLastError();
CString str;
str.Format("连接失败,错误码:%d",error);
AfxMessageBox(str);
return 0;
break;
}
}
m_bConnnected = TRUE;
while(1)
{
if(pView->m_bEndThread ) //如果要退出线程
{
break;
}
if(pView->m_bPauseThread) //如果要暂停线程
{
Sleep(10); //线程休眠
}
else //如果线程正常
{
if(m_bConnnected)
{
int send_length = socket.Send("123",3,0); //发送一般返回的都是发送的长度,发送不会返回错误
int rev_length = socket.Receive(buf,255,0); //如果没有错误发生,接收返回的是实际接收的长度,
//如果连接已经断开,接收返回的是0,但是这个时候其实不算错误发生。所以可以从返回值判断连接是否断开。
if(rev_length == 0) //表名连接断开
{
m_bConnnected = FALSE;
}
}
else //重试10次连接
{
SocketConnectRetryTime++;
if(SocketConnectRetryTime < 10) //重连10次
{
if(socket.m_hSocket)
{
socket.Close();
}
socket.Create();
if(socket.Connect("127.0.0.1",20000)) //如果连接成功。
{
m_bConnnected = TRUE;
SocketConnectRetryTime = 0;
}
}
else //如果10次都没有连接成功,则弹出连接断开,请检查网络。
{
DWORD error = GetLastError(); //其实这个时候错误为0,就是是正常的。
CString str;
str.Format("%d",error);
AfxMessageBox("连接断开,请检查网络。"+str);
break;
}
}
}
}
pView->m_bEndThread = FALSE;
return 0; //函数正常返回
}
我的线程启动函数,视图中有3个按钮,启动按钮,暂停按钮,结束按钮:
启动按钮:
void CSocketView::OnBtnStartThread()
{
ThreadID = IDC_THREAID;
if(pThread == NULL)
{
pThread = AfxBeginThread(ThreadFun, this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
pThread->ResumeThread();
m_BtnStartThread.EnableWindow(FALSE);
m_BtnPauseThread.EnableWindow(TRUE);
m_BtnEndThread.EnableWindow(TRUE);
}
}
暂停按钮:
void CSocketView::OnBtnPauseThread()
{
if(m_bPauseThread) //如果已经暂停
{
m_bPauseThread = FALSE;
m_BtnPauseThread.SetWindowText("暂停线程");
}
else
{
m_bPauseThread = TRUE;
m_BtnPauseThread.SetWindowText("继续线程");
}
}
停止按钮:这里最重要的就是这个停止了。
我开始的方式是设置停止标志为TRUE。这样的效果是最好的,线程函数正常返回,但是当socket接收阻塞的时候,线程函数的while(1)也是卡住的,所以即使线程结束标志被置位为1,线程函数也不能响应。并且在socket不阻塞的时候,多次开启线程,结束线程,程序使用的内存大概会每5次增长4KB。我好奇的是,不是说线程函数的自动返回会清除线程所有的资源吗,检查了很久也没有找到为什么内存会增长。
void CSocketView::OnBtnEndThread() //结束线程
{
m_bEndThread = TRUE;
m_BtnStartThread.EnableWindow(TRUE);
m_BtnPauseThread.EnableWindow(FALSE);
m_BtnEndThread.EnableWindow(FALSE);
}
由于担心SOCKET阻塞的时候,线程函数不能响应标志和消息,于是采用强行结束内存的方式。
void CSocketView::OnBtnEndThread() //结束线程
{
DWORD dwExitCode = 0 ;
GetExitCodeThread(pThread->m_hThread,&dwExitCode);
TerminateThread(pThread->m_hThread,dwExitCode);
CloseHandle(pThread->m_hThread);
pThread = NULL;
m_BtnStartThread.EnableWindow(TRUE);
m_BtnPauseThread.EnableWindow(FALSE);
m_BtnEndThread.EnableWindow(FALSE);
}
这种方式,每关闭一次线程,再开启,程序的内存增长更快,每次增长4KB。我不知道该怎么来释放线程的资源了。由于我的程序会经常的关闭和开启线程,所以是不能允许这样的情况的,在此贴出来和大家一起探讨~
12 个解决方案
#1
楼主:
1、你这么长篇大论最好用一下代码那个功能,要不真没法看;
2、AfxSocketInit 一个程序用一次就行;
3、两个解决方法,一个是准备一个event,在线程退出后signal,stop里一直等到这个event再返回,保证每次都安全退出;二是修改线程为线程池,新建时候如果有可用的就不真的新建。
1、你这么长篇大论最好用一下代码那个功能,要不真没法看;
2、AfxSocketInit 一个程序用一次就行;
3、两个解决方法,一个是准备一个event,在线程退出后signal,stop里一直等到这个event再返回,保证每次都安全退出;二是修改线程为线程池,新建时候如果有可用的就不真的新建。
#2
1 最稳妥的结束方式,是让线程函数自己返回。
2 AfxSocketInit你调用了多少次?这个函数应该是封装了WSAStartup,一个应用程序只需要启动时调用一次就行。
3 内存泄漏其实并不难检测,试试DebugDiag;http://blogs.msdn.com/b/tess/archive/2010/01/14/debugging-native-memory-leaks-with-debug-diag-1-1.aspx
2 AfxSocketInit你调用了多少次?这个函数应该是封装了WSAStartup,一个应用程序只需要启动时调用一次就行。
3 内存泄漏其实并不难检测,试试DebugDiag;http://blogs.msdn.com/b/tess/archive/2010/01/14/debugging-native-memory-leaks-with-debug-diag-1-1.aspx
#3
我知道最理想的方式还是函数自己返回,但是在while(1)中,比如:
while(1)
{
if(m_flag)
{
socket.send(txbuf,3);
socket.recevie(rxbuf,255);
}
else
{
return 0;
}
}
要让函数返回,只需要设置m_flag等于false就可以,但是如果socket阻塞在接收的时候,这个时候设置m_flag也是没有用的,一定要等recevie返回后,才能跳出while(1).
while(1)
{
if(m_flag)
{
socket.send(txbuf,3);
socket.recevie(rxbuf,255);
}
else
{
return 0;
}
}
要让函数返回,只需要设置m_flag等于false就可以,但是如果socket阻塞在接收的时候,这个时候设置m_flag也是没有用的,一定要等recevie返回后,才能跳出while(1).
#4
1 阻塞模式(你正在用的): 设置send、receive的timeout;
2 非阻塞模式: 用select,select里设置timeout;
#5
设置socket的SO_SNDTIMEO, SO_RCVTIMEO
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740532%28v=vs.85%29.aspx
#6
你创建一个线程,不需要频繁的销毁创建吧。给线程发送消息PostThreadMessage(),线程函数根据消息的不同做不同的逻辑处理即可。真正需要销毁线程的时候也可以发送消息到线程,线程接收到消息以后return返回
#7
SetSockOpt不能设置SO_SNDTIMEO, SO_RCVTIMEO ,设置超时,只能设置SOCKET对象,不能设置CSocket对象:
Berkeley Software Distribution (BSD) options not supported for SetSockOpt are:
Value Type Meaning
SO_ACCEPTCONN BOOL Socket is listening
SO_ERROR int Get error status and clear.
SO_RCVLOWAT int Receive low water mark.
SO_RCVTIMEO int Receive timeout
SO_SNDLOWAT int Send low water mark.
SO_SNDTIMEO int Send timeout.
#8
其实不用频繁创建的,能挂起再恢复也可以,现在是因为socket阻塞了线程,导致线程也不能响应消息的~要让线程停止下来,只有使用结束线程才能停止。
#9
这个还是换成了非阻塞的来做,才不会出现现在的问题。
#10
lz解决掉了么?我也遇到了 帮帮忙呗
#11
我马上也和楼主一样面临这个问题了,先mark一下
另外 ,我准备使用
PostThreadMessage(thread->m_nThreadID , WM_QUIT , 0 , 0);
看能否从阻塞中退出,暂时还没有测试
另外 ,我准备使用
PostThreadMessage(thread->m_nThreadID , WM_QUIT , 0 , 0);
看能否从阻塞中退出,暂时还没有测试
#12
用非阻塞如何做?
#1
楼主:
1、你这么长篇大论最好用一下代码那个功能,要不真没法看;
2、AfxSocketInit 一个程序用一次就行;
3、两个解决方法,一个是准备一个event,在线程退出后signal,stop里一直等到这个event再返回,保证每次都安全退出;二是修改线程为线程池,新建时候如果有可用的就不真的新建。
1、你这么长篇大论最好用一下代码那个功能,要不真没法看;
2、AfxSocketInit 一个程序用一次就行;
3、两个解决方法,一个是准备一个event,在线程退出后signal,stop里一直等到这个event再返回,保证每次都安全退出;二是修改线程为线程池,新建时候如果有可用的就不真的新建。
#2
1 最稳妥的结束方式,是让线程函数自己返回。
2 AfxSocketInit你调用了多少次?这个函数应该是封装了WSAStartup,一个应用程序只需要启动时调用一次就行。
3 内存泄漏其实并不难检测,试试DebugDiag;http://blogs.msdn.com/b/tess/archive/2010/01/14/debugging-native-memory-leaks-with-debug-diag-1-1.aspx
2 AfxSocketInit你调用了多少次?这个函数应该是封装了WSAStartup,一个应用程序只需要启动时调用一次就行。
3 内存泄漏其实并不难检测,试试DebugDiag;http://blogs.msdn.com/b/tess/archive/2010/01/14/debugging-native-memory-leaks-with-debug-diag-1-1.aspx
#3
我知道最理想的方式还是函数自己返回,但是在while(1)中,比如:
while(1)
{
if(m_flag)
{
socket.send(txbuf,3);
socket.recevie(rxbuf,255);
}
else
{
return 0;
}
}
要让函数返回,只需要设置m_flag等于false就可以,但是如果socket阻塞在接收的时候,这个时候设置m_flag也是没有用的,一定要等recevie返回后,才能跳出while(1).
while(1)
{
if(m_flag)
{
socket.send(txbuf,3);
socket.recevie(rxbuf,255);
}
else
{
return 0;
}
}
要让函数返回,只需要设置m_flag等于false就可以,但是如果socket阻塞在接收的时候,这个时候设置m_flag也是没有用的,一定要等recevie返回后,才能跳出while(1).
#4
1 阻塞模式(你正在用的): 设置send、receive的timeout;
2 非阻塞模式: 用select,select里设置timeout;
#5
设置socket的SO_SNDTIMEO, SO_RCVTIMEO
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740532%28v=vs.85%29.aspx
#6
你创建一个线程,不需要频繁的销毁创建吧。给线程发送消息PostThreadMessage(),线程函数根据消息的不同做不同的逻辑处理即可。真正需要销毁线程的时候也可以发送消息到线程,线程接收到消息以后return返回
#7
SetSockOpt不能设置SO_SNDTIMEO, SO_RCVTIMEO ,设置超时,只能设置SOCKET对象,不能设置CSocket对象:
Berkeley Software Distribution (BSD) options not supported for SetSockOpt are:
Value Type Meaning
SO_ACCEPTCONN BOOL Socket is listening
SO_ERROR int Get error status and clear.
SO_RCVLOWAT int Receive low water mark.
SO_RCVTIMEO int Receive timeout
SO_SNDLOWAT int Send low water mark.
SO_SNDTIMEO int Send timeout.
#8
其实不用频繁创建的,能挂起再恢复也可以,现在是因为socket阻塞了线程,导致线程也不能响应消息的~要让线程停止下来,只有使用结束线程才能停止。
#9
这个还是换成了非阻塞的来做,才不会出现现在的问题。
#10
lz解决掉了么?我也遇到了 帮帮忙呗
#11
我马上也和楼主一样面临这个问题了,先mark一下
另外 ,我准备使用
PostThreadMessage(thread->m_nThreadID , WM_QUIT , 0 , 0);
看能否从阻塞中退出,暂时还没有测试
另外 ,我准备使用
PostThreadMessage(thread->m_nThreadID , WM_QUIT , 0 , 0);
看能否从阻塞中退出,暂时还没有测试
#12
用非阻塞如何做?