源代码下载:http://www.vckbase.com/code/downcode.asp?id=2975
相关文章:http://www.vckbase.com/document/viewdoc/?id=1706建立一个基于对话框的工程MultiThread5,在对话框IDD_MULTITHREAD5_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始” ,一个进度条IDC_PROGRESS1; 
打开ClassWizard,为编辑框IDC_MILLISECOND添加int型变量m_nMilliSecond,为进度条IDC_PROGRESS1添加CProgressCtrl型变量m_ctrlProgress; 
在MultiThread5Dlg.h文件中添加一个结构的定义:
struct threadInfo
{
UINT nMilliSecond;
CProgressCtrl* pctrlProgress;
};线程函数的声明:UINT ThreadFunc(LPVOID lpParam); 
注意,二者应在类CMultiThread5Dlg的外部。在类CMultiThread5Dlg内部添加protected型变量:CWinThread* pThread; 
在MultiThread5Dlg.cpp文件中进行如下操作:定义公共变量:threadInfo Info; 
双击按钮IDC_START,添加相应消息处理函数:void CMultiThread5Dlg::OnStart() 
{
// TODO: Add your control notification handler code here UpdateData(TRUE);
Info.nMilliSecond=m_nMilliSecond;
Info.pctrlProgress=&m_ctrlProgress; pThread=AfxBeginThread(ThreadFunc,
&Info);
}在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句: 
{
……

// TODO: Add extra initialization here
m_ctrlProgress.SetRange(0,99);
m_nMilliSecond=10;
UpdateData(FALSE);
return TRUE;  // return TRUE  unless you set the focus to a control
}添加线程处理函数: 
UINT ThreadFunc(LPVOID lpParam)
{
threadInfo* pInfo=(threadInfo*)lpParam;
for(int i=0;i<100;i++)
{
int nTemp=pInfo->nMilliSecond; pInfo->pctrlProgress->SetPos(i); Sleep(nTemp);
}
return 0;
}当线程正在运行时点击右上角的关闭按钮,然后查看输出窗口得到下面的内容:
线程 'Win32 线程' (0xc8c) 已退出,返回值为 2 (0x2)。
线程 'Win32 线程' (0x514) 已退出,返回值为 2 (0x2)。
Detected memory leaks!
Dumping objects ->
f:\rtm\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306) : {97} client block at 0x003A7778, subtype c0, 68 bytes long.
a CWinThread object at $003A7778, 68 bytes long
Object dump complete.
程序“[1740] MultiThread5.exe: 本机”已退出,返回值为 2 (0x2)。红色部分为内存泄露信息
暂且不说有没有必要避免这个问题,我想知道有什么办法解决这个问题。

解决方案 »

  1.   

    补充一下,是用vs2005看到这个内存泄露的信息的,vc++6.0并不提示这个信息。
      

  2.   

    假设不强制关闭。当线程中这样:
    while(1)
    {
      ......
      ......
      Sleep(2000);//当我的程序要退出时刚好运行到这句,那么主程序怎么才能知道这个线程结束?
      ....
    }
    换句话说,当线程正在运行时,我要退出程序,怎么才可以安全的退出。
      

  3.   

    用waitforsingleobject等待退出event
      

  4.   

    一般不这么强制退出的
    for循环里写个Bool变量标记是否继续循环
    外部设置这个变量 然后用定时器等待线程退出即可
    不要在UI线程里WaitForSingleObject无限等待!
      

  5.   

    首先:你的子线程应该有个机制,让主线程通知它退出。例如设置一个全局变量,当全局变量设置为true时,子线程必须退出
    其次:每个子线程必须不阻塞超过太长时间,例如500ms它必须检查这个标志一次
    再次:主线程应该用WaitForSingleObject等待子线程退出
      

  6.   

    http://www.microsoft.com/MSJ/archive/SFFF.aspx
    参考Jeffrey Richter 的处理模式
      

  7.   

    顶楼上。让线程控制函数返回是常规的方法。
    可以用全局变量或者事件对象。在线程里如果检测到这个全局变量置为标志退出的值或者事件对象为有信号状态,就return。
    还有不要在线程里如下更新主线程界面 pInfo->pctrlProgress->SetPos(i);
    而要通过给主窗口寄送消息的方式,让主窗口自己来更新。
      

  8.   

    sleep(2000)这个可以优化, 也就是说如果线程准备退出的话 不用 sleep(2000);更改如下:void CPRRAlarmNotificationDlg::mf_Sleep(DWORD dwMS, const BOOL &bStop)
    {
    DWORD dwTickstart = GetTickCount();
    while(!bStop)
    {
    if ( (GetTickCount() - dwTickstart) > dwMS)
    {
    break;
    } Sleep(1);
    }
    }线程一般自然退出最好. 强制退出非必要不要使用, 可以用如下代码: m_bStopThread为线程死循环的变量,
    m_pThread为线程指针. m_bStopThread = TRUE; while (m_pThread != NULL)
    {
    MSG msg;
    if(PeekMessage(&msg, m_hWnd, 0, 0, PM_NOREMOVE))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    } Sleep(30);
    }
      

  9.   

    说明一点:在windows下,如果程序退出了,泄漏的内存是会被系统自动回收的
    不过其它资源就难说了,比如某某设备等
      

  10.   

    注意,在多任务系统中应该尽量避免使用下面代码,这样的代码会导致CPU不停被占用,影响系统性能。if ( (GetTickCount() - dwTickstart) > dwMS)
            {
                break;
            }
      

  11.   

    我在说下,可能我没描述清楚。
    while(1)
    {
      ......
      ......
      Sleep(2000);//当我的程序要退出时刚好运行到这句,那么主程序怎么才能知道这个线程结束?
      ....
    }
    当我的程序要退出时刚好运行到这句,那么主程序怎么才能知道这个线程结束?
    大家注意看我这句话,我退出程序的时候刚好运行到Sleep(2000)这句,怎么办?但是退出时主程序并不知道运行到哪句了。
    我既然用了Sleep(2000)就不存在优化之类的说法了,例如我写个定时器,两秒检测一下,你给我改成Sleep(1)我程序就没法用了是吧。
      

  12.   


    汗, 我的意思是你用mf_Sleep(2000, bStop); 来代替 Sleep(2000);
      

  13.   

    线程最好不要强制退出在退出的时候设置一个变量让线程自己退出,
    并在主线程中用WaitForSingleObject等待线程句柄等线程自己退出后再结束主线程
      

  14.   

    mf_Sleep在哪?我怎么找不到...
      

  15.   

    前面不是一直有人告诉你WaitForSingleObject么?
      

  16.   

    【一】我一般开线程都开UI线程的,要做类似循环的操作的话,是利用在UI线程中绑定(创建)个窗口,利用窗口中的Timer来实现的,因为一般来说释放UI线程的话,可以发个消息给UI线程,线程就可以自己摧毁自己了(安全地)
    优点:安全、逻辑清晰、适用于多线程处理复杂的业务逻辑、很方便支持线程消息
    缺点:资源开销偏大(其实也大不了多少)【二】工作线程的话,如果是纯粹的循环业务处理的工作线程,可以再每次循环的入口或者业务间隙点里增加一个型号对象(一般用Event),如果要退出此线程(循环操作),在任何地方SetEvent一下就行了,当事件触发后,就会跳出循环了。
    优点:占用资源少
    缺点:一般工作线程是处理一些独立的业务,交互性较差(相对)【总结】
    不管是工作线程还是UI线程最后退出的时候,都尽量做到用WaitForSingleObject来判断线程对象是否已经退出,超时时间不能是永久,一般是根据具体的业务析构的复杂度来自己判定……************************************************************************************
    以上只是个人的一些经验谈,不一定一定对,呵呵!
    相互学习……
      

  17.   


    void CPRRAlarmNotificationDlg::mf_Sleep(DWORD dwMS, const BOOL &bStop)
    {
        DWORD dwTickstart = GetTickCount();
        while(!bStop)
        {
            if ( (GetTickCount() - dwTickstart) > dwMS)
            {
                break;
            }        Sleep(1);
        }
    }这个不是我给你的代码吗?汗. lz应该仔细看看回复.
      

  18.   

    WaitForObject,还有,把线程里面的m_bAuto..(忘了具体怎么写)置为FALSE,退出的时候手动delete m_pThread
      

  19.   


    用 waitforsingleobject 等待线程句柄释放 , 不能无限等待 , 再用全局变量做后备,
    如果线程死或者不知道卡在哪里 , Terminate.至于sleep(2000) , 线程里最好别用.
      

  20.   

    简单的问题不要弄复杂了,写代码要懂得化繁为简,就用我说的第二种方案就行了:【二】工作线程的话,如果是纯粹的循环业务处理的工作线程,可以再每次循环的入口或者业务间隙点里增加一个型号对象(一般用Event),如果要退出此线程(循环操作),在任何地方SetEvent一下就行了,当事件触发后,就会跳出循环了。