有代码如下:
bool g_IsReadThreadFinish = true;DWORD WINAPI ReadData(LPVOID lpParameter)
{
g_IsReadThreadFinish = false;//线程开始 //处理过程
.......; g_IsReadThreadFinish = true;//线程结束 return 0;
}CXXXDlg::OnBnClickedBtnSelect()
{
vector<string>::iterator iterator = vectorTab.begin();
while (iterator != vectorTab.end())
{
.......; DWORD WINAPI ReadData(LPVOID lpParameter);
HANDLE handle=CreateThread(NULL,0,ReadData,NULL,0,NULL);
CloseHandle(handle);
g_IsReadThreadFinish = false; while (!g_IsReadThreadFinish)
{
Sleep(200);
}
iterator++;
}
}主线程的OnBnClickedBtnSelect()函数要连续几次通过创建相同线程进行处理,线程参数不一样
1.建线程后,将g_IsReadThreadFinish = false;
2.在线程处理函数中g_IsReadThreadFinish = false;
3.线程处理函数结束,g_IsReadThreadFinish = true;
4.主现成开启线程后进入while (!g_IsReadThreadFinish)
{
Sleep(200);
}等待;
这样看起来没有出问题,可是调试的时候,怎么第一个线程都还没处理完,主线程又开启第二个线程了呢?
请指点!!!

解决方案 »

  1.   

    创建线程之前g_IsReadThreadFinish = false;
      

  2.   


    你的线程函数又没有进行互斥的判断。而且你这样简单的线程设计在开启多个线程函数后会有问题的。如果能确定线程函数的个数,建议你去看看WaitForMultiObject函数的用法,这才应该是标准的线程等待方法。
      

  3.   

    我创建线程后就让g_IsReadThreadFinish 为false,且让主线程等待
    while (!g_IsReadThreadFinish)
            {
                Sleep(200);
            }知道,创建的线程结束
      

  4.   

    这句话只要放在
    while (!g_IsReadThreadFinish) 
            { 
                Sleep(200); 
            } 
    之前应该就有效果啊?并且在第一个创建的线程执行的前期过程
    while (!g_IsReadThreadFinish) 
            { 
                Sleep(200); 
            } 
    语句是起了作用的
      

  5.   

    如果在创建线程之后g_IsReadThreadFinish = false,则有可能导致下面死循环。
      

  6.   

    开始时没注意你的问题是创建了多于一个的线程,这估计是有内存越界或者使用了错误的指针而破坏了g_IsReadThreadFinish的值。
      

  7.   

    刚才也没修改什么可是现在运行的时候出现新的问题:
    就是创建的第一个线程执行一段时间后,但还没结束,好象在现成中就始终运行不走了------按F10后,虽然还是在两个线程中切换,在创建的线程中找不到运行位置的提示了
    所以主现成也始终处于睡眠状态了我在创建的线程入口函数结束前有语句
    g_IsReadThreadFinish = true;//线程结束可是该入口函数根本就执行不到这一句来,在中间某个位置就不走了
      

  8.   

    bool g_IsReadThreadFinish = true;
    //DWORD WINAPI ReadData(LPVOID lpParameter);
    if(g_IsReadThreadFinish){
        g_IsReadThreadFinish = false;
        HANDLE handle=CreateThread(NULL,0,ReadData,NULL,0,NULL);  
    }
    DWORD WINAPI ReadData(LPVOID lpParameter)
    {
        //g_IsReadThreadFinish = false;//线程开始    //处理过程
        .......;    g_IsReadThreadFinish = true;//线程结束
        return 0;
    }
      

  9.   

    刚才不让连续回复现在补上:当我让创建线程只执行一次的时候 同时把Sleep(200)注释掉,这样现成入口函数可以完全执行.不知道是什么道理
      

  10.   

    因为Sleep的功能是暂停当前线程的CPU使用功能,切换到其他的线程去执行,你现在的代码很可能执行在主线程的while-Sleep循环中,每次执行到Sleep,然后线程切换到你创建的线程,而系统会发现所创建的线程执行的时间过长,系统又把CPU调度给你的主线程,这里就形成了一个来回的死循环。我之前的回复可能没考虑好,但仍然建议你用WaitForSingleObject方法来等待线程结束
      

  11.   

    好的,我找你的方法看看不过,想不通的是,为什么创建的线程执行到一段时间后,就不会继续执行下去,这样也造成了主线程的无休止睡眠.
    但是,当我让创建线程只执行一次的时候 同时把Sleep(200)注释掉,这样现成入口函数可以完全执行
      

  12.   

    ,而系统会发现所创建的线程执行的时间过长,系统又把CPU调度给你的主线程,这里就形成了一个来回的死循环----------------------
    能这样理解吗?系统发现创建的线程执行的时间过长,就根本不会给创建的线程一段时间--时间片,让创建的线程执行下去,而是马上有把CPU调度分配给主线程?
      

  13.   

    在c++中编译时,如果发现在函数体内部没有改变某个变量的值,如g_IsReadThreadFinish,则函数体可能忽略该项值的检测,直接用初始值来代替,也就是说在OnBnClickedBtnSelect()函数体内,g_IsReadThreadFinish永远被编译成了false.试试使用volatile bool g_IsReadThreadFinish = true;替换原来的bool g_IsReadThreadFinish = true;
      

  14.   

    这个问题难到我了利用互斥对象后仍然在创建的线程中执行一段代码后,就不知道执行到那里去了.始终执行不完这样主线程始终也得不到互斥对象的所有权,代码如下:
    HANDLE g_hMutex;DWORD WINAPI ReadData(LPVOID lpParameter)
    {
    WaitForSingleObject(g_hMutex,INFINITE);//线程开始 .......;//读取数据库,获得相关数据 .......;//将得到的数据显示在CListCtrl上 ReleaseMutex(g_hMutex);//线程结束 return 0;
    }CXXXDlg::OnBnClickedBtnSelect()
    {
    ...........
    g_hMutex = CreateMutex(NULL,false,NULL); vector<string>::iterator iterator = vectorTab.begin();
    while (iterator != vectorTab.end())
    {
    WaitForSingleObject(g_hMutex,INFINITE);
    .......; DWORD WINAPI ReadData(LPVOID lpParameter);
    HANDLE handle=CreateThread(NULL,0,ReadData,NULL,0,NULL);
    CloseHandle(handle); ReleaseMutex(g_hMutex);
    Sleep(10);  //确保创建的现成获得g_hMutex; iterator++;
    }
    }在ReadData函数中,
    当把".......;//读取数据库,获得相关数据"部分运行完后既而再运行".......;//将得到的数据显示在CListCtrl上"部分时,就不知道运行到那里去了所以主线程也始终获得不了g_hMutex当只创建一个线程的时候,所以也不用加上利用Mutex实现同步,
    ReadData就能很好的完成.
      

  15.   

    在线程中访问控件可能会导致错误,因为VC中的控件都不是线程安全的,最好是通过SendNotifyMessage或者PostMessage,向控件发送消息来刷新显示,或者向窗口发送自定义消息,来处理。
      

  16.   

    线程中发送PostMessage很容易导致死锁的。
      

  17.   

    根据你的代码中得到的提示信息,你应该不能用WaitForSingleObject函数,原因在于这个函数是阻塞主线程的消息循环来等待,而你的ReadData线程会去操作CListCtrl来显示数据,这样会导致两个线程都阻塞住。你的问题需要判断你的线程函数ReadData会和界面的相关吗?或者说这个函数会涉及到主线程的消息泵吗?
    如果你的回答是不,那么可以才可以用WaitForSingleObject来等待,我看你对WaitForSingleObject的用法好像也有问题。你应该用MsgWaitForMultipleObjects,这个函数才是既等待内核对象,又处理消息的。下面的while循环才是用来实现你的真正的等待,代码段仅供参考while(TRUE)
    {
        DWORD result ; 
        MSG msg ; 
        result = MsgWaitForMultipleObjects(1, &readThreadHandle, 
            FALSE, INFINITE, QS_ALLINPUT); 
        if (result == (WAIT_OBJECT_0))
        {
            break;
        } 
        else 
        { 
            PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
            DispatchMessage(&msg); 
        } 
    }
      

  18.   

    判断线程是否执行完可以直接判断线程句柄。
    m_hThread=CreateThread();
    WaitForSingleObject(m_hThread,INITFINE);
    就可以了吧
      

  19.   


    请注意我前面的分析,楼主的线程函数也需要操作控件,不能简单的用WaitForSingleObject,会阻塞两个线程的,因为操作控件很可能会使用SendMessage这样的调用
      

  20.   

    可是调试的时候,怎么第一个线程都还没处理完,主线程又开启第二个线程了呢? 
    ——————
            HANDLE handle=CreateThread(NULL,0,ReadData,NULL,0,NULL);
            CloseHandle(handle);
            g_IsReadThreadFinish = false;        while (!g_IsReadThreadFinish)
            {
                Sleep(200);
            }
    ——————
    注意:CloseHandle(handle)并不是结束线程,而是释放线程句柄handle的资源。另外,进程的主线程有比子线程更高的优先级。
    所以,上面代码中,线程创建后,还没等线程结束,而仅仅是当线程句柄释放后就急急地把g_IsReadThreadFinish设为false了。从你的描述来看,g_IsReadThreadFinish = false;这一句应当放到线程处理函数ReadData执行完毕前的最后一句处。
      

  21.   


    为什么用WaitForSingleObject会导致ReadData线程阻塞呢?
    对这个不理解,麻烦解释下
      

  22.   


    还有几点不清楚:
    1.为什么用WaitForSingleObject会导致ReadData线程阻塞呢? 这个不理解
    2.怎么判断和界面相关呢? 这是一个基于对话框的程序,在按钮的响应函数里通过创建线程读数据,然后显示在对话框上的CListCtrl.
      感觉是和界面相关的,可是能确定
    3.对你所列出的例子,因为以前没见过MsgWaitForMultipleObjects函数,
      根据你的提示,我的理解如下,不知道对不对,请指正:
         a.MsgWaitForMultipleObjects函数跟WaitForSingleObject不一样,后者是通过阻塞主线程消息循环来达到等待,所以当在ReadData线程操作主线程(对话框)上的
            CListCtrl时,因为ReadData线程是通过向主线程发送某个消息来实现的.所以这时由于主线程处于阻塞状态,处理不了这个消息,从而导致了ReadData线程也处于一直 
            等待状态,
         b.MsgWaitForMultipleObjects是不是阻塞主线程消息循环的,他根据返回的值,来判断执行何种操作.当等于WAIT_OBJECT_0,跳出该次循环,当不是,怎么处理消息
      麻烦解释下,再次感谢了!
      

  23.   

    补充:b.MsgWaitForMultipleObjects是不是阻塞主线程消息循环的,他根据返回的值,来判断执行何种操作.当等于WAIT_OBJECT_0,跳出该次循环,当不是,怎么处理消息
            再看时,又有疑惑了:
           if (result == (WAIT_OBJECT_0)),你用的是break,即结束循环,
           如果用的是continue,我能理解.在主线程的执行时间周期里,不停的判断MsgWaitForMultipleObjects的返回值,当result == (WAIT_OBJECT_0)时,跳出本次循环
            ,如果不是,责表明有其他消息(ReadData线程操作CListCtrl传来的)传来需要处理,如果主线程的时间周期还没结束,就处理该消息.当主线程执行时间周期结束后,又
            把CPU控制全转交给ReadData线程,如果对CListCtrl的操作已经完成,那么ReadData线程线程就继续执行操作CListCtrl之后的代码
            
      

  24.   

    如果用多线程,主线程建立一个线程后不应等待,否则不如直接把楼主代码的CreateThread()换成ReadData(),效率不是更高一些吗?
    应该明确线程争用的资源是什么,在子线程中控制访问冲突。
      

  25.   

    创建线程之前g_IsReadThreadFinish = false;
      

  26.   

    volatile
    前面有人说了, 编译器优化的问题
      

  27.   

    1.
    你的a这点的理解基本正确的,这也回答了你的第一个问题。
    2.
    判断的方式很简单,你就看ReadData中你是如何操作CListCtrl的,可以需要进一步阅读MFC的代码。
    3.MsgWaitForMultipleObjects的用法就是我上面给的代码
      

  28.   

    我在实际使用中发现CloseHandle(handle)不一定能关闭和退出创建的线程.具体什么原因我现在也没有找到,应该就是这个原因造成线程不停创建.
    我的做法是在新建线程的代码中设定一个变量,然后根据这个变量直接Return来退出线程.
      

  29.   


    谢谢,你给的例子里
    if (result == (WAIT_OBJECT_0)) 
        { 
            break; 
        } 
    break能换成continue吗?
    这样理解:
    在主线程的执行时间周期里,不停的判断MsgWaitForMultipleObjects的返回值,当result == (WAIT_OBJECT_0)时,跳出本次循环 
     继续下次循环,如果不是,责表明有其他消息(ReadData线程操作CListCtrl传来的)传来需要处理,如果主线程的时间周期还没结束,就处理该消息.当主线程执行时间周期结束后,
    就把CPU控制全转交给ReadData线程,如果对CListCtrl的操作已经完成,那么ReadData线程线程就继续执行操作CListCtrl之后的代码
      

  30.   

    楼上没一个人说到点子上的。
    LZ是想用Sleep来代替烦人的互斥对象,这个最好放在线程内部随便设一个全局变量 b=false;
    [code=C/
    DWORD WINAPI ReadData(LPVOID lpParameter)
    {
        while(b)
          Sleep(1);      b=true;    ...
        ...
         ...
           b=false;
       return 0;
    }       C++][/code]
      

  31.   

      在主線程使用sleep是導致線程同步異常的根源。
      在主線程創建互斥量,也在主線程釋放,保證只有一個線程在運行。次線程中不要去釋放互斥量。
      

  32.   

      還有線程也有相對優先級,不需要通過sleep來讓主線程獲得控制權。
      

  33.   

    这种问题, 只能说是naive, lz不知道同步对象的作用吗, 用全局变量来互斥访问, 你让主线程怎么等待, 用sleep, 太搞笑了...
      

  34.   

    都回答的些什么啊?无语了!!
    楼主你的线程函数里面前面不要WaitForSingleObject了,你前面已经在主线程中
    使用WaitForSingleObject了,所以线程函数中等待就会死锁,挂在那里,所以系统就挂了。
    只要把线程函数前的WaitForSingleObject去掉就可以了。
    还有你如果调试不要只在主线程中打断点然后按F10,在子线程中也打个断点,然后按F10,
    这样你就可以看到程序在两个线程中切换执行了。
      

  35.   


    请注意,ReadData线程里没有使用你说的while(b)的循环,而是处理完了就执行b=false; 
    之所以出现最后2个线程等待的原因,应该还是如同22楼分析的那样,主线程已经Sleep了,由于在ReadData线程有和界面相关,所以导致了两个线程都阻塞住欢迎探讨
      

  36.   

    楼主,你用sleep也是可以的。可以实现你想要的功能,你如果调试在子线程和主线程中都打个断点,然后按F10来调试,这样才可以看到程序在2个线程中切换来执行。。
    用WaitForSingleObject导致你程序死锁是因为你在子线程中也用了WaitForSingleObject,只要把子线程中的WaitForSingleObject去掉就行了。。
    还有这里不需要判断返回值,因为你时间指定的是INFINITE
      

  37.   


    觉得不是这个原因:ReadData线程只是在处理跟界面相关代码的时候发生阻塞的,应该不能用WaitForSingleObject,而是用MsgWaitForMultipleObjects,如同22楼说的个道理
      

  38.   

    如果楼主的数据线程里面没有去操作CListCtrl,是可以用WaitForSingleObject的,但是线程中一旦用了SendMessage之类的方法就不行了
      

  39.   


    晕死。你先搞清楚WaitForSingleObject的意思再说吧。如果一个线程调用了WaitForSingleObject锁住g_hMutex另外一个线程再调用WaitForSingleObject还能继续才怪呢!!
    22楼那个有什么用啊。你又不是多个事件对象。有毛用。。
      

  40.   


    没注意楼主代码中主线程也有ReleaseMutex,呵呵。。
      

  41.   

    兄弟,麻烦文明点,咱们知识在探讨,又不是在吵架请你先看清楚问题再说,现在的问题是ReadData线程运行到到中间的时候出现2个线程阻塞的问题,二不是你所说的
      

  42.   


    我在ReadData线程里,没有使用SendMessage,也没PostMessage,
    而是在GetDlgItem来获取CListCtrl的,进而向CListCtrl中插入数据,请问这算界面相关吗?
      

  43.   

    我在ReadData线程里,没有使用SendMessage,也没PostMessage, 
    而是在ReadData线程通过GetDlgItem来获取CListCtrl的,进而向CListCtrl中插入数据,请问这算界面相关吗?
      

  44.   

    while (iterator != vectorTab.end())
        {
            .......;        DWORD WINAPI ReadData(LPVOID lpParameter);
            HANDLE handle=CreateThread(NULL,0,ReadData,NULL,0,NULL);
            CloseHandle(handle);
            g_IsReadThreadFinish = false;        while (!g_IsReadThreadFinish)
            {
                Sleep(200);
            }
            iterator++;
        }
    你这段代码有问题 当然会不停创建啦。
    你简化一下看看?
    while(p->next!= null)
    {
      createthread;
      nn = false;
      if(!nn) sleep(200)
       p = p->next;
    }
    你这段代码的意思是 如果p不为空 创建线程 等待200毫秒 p指向下一个对象
    如果下一个对象有 那么接着创建线程。。在200毫秒。。如此重复。
    这么多高手 难道都没有看出来吗?
    你们的解决方法我不懂。
    但是这段代码它就是会不停创建。
      

  45.   

    ::InitializeCriticalSection(&m_CriticalSectionLock);::EnterCriticalSection(&m_CriticalSectionLock);
    g_IsReadThreadFinish = false; 
    ::LeaveCriticalSection(&m_CriticalSectionLock);
      

  46.   

    sleep()函数时间太长,而且该函数运行后程序暂停,包括主线成。可以试试Getendcode函数。
      

  47.   

    sleep()函数时间太长,而且该函数运行后程序暂停,包括主线成。可以试试Getendcode函数。
      

  48.   

    sleep()函数时间太长,而且该函数运行后程序暂停,包括主线成。可以试试Getendcode函数。
      

  49.   

    楼主我很不明白你的意图!
    首先你是不是想启动一个后台线程帮你处理vectorTab里面的数据。
    如果是的话什么需要处理一个vectorTab里面的元素就创建一个线程。
    其实一开是的while循环就可以放在后台线程中的。
    然后你说第一个线程还未执行完就产生第二个线程,这个问题我使过了好像是不会出现的。代码如下:
    bool g_IsReadThreadFinish = true;DWORD WINAPI ReadData(LPVOID lpParameter)
    {
    int r=(int)lpParameter;
    g_IsReadThreadFinish = false;//线程开始 cout<<"线程"<<r<<"执行当中!"<<endl; g_IsReadThreadFinish = true;//线程结束
             cout<<"线程"<<r<<"结束!"<<endl;
    return 0;
    }
    void main()
    {
    int i=0;
    while(1)
    {
            HANDLE threadHandle=CreateThread(NULL,0,ReadData,(LPVOID)i,0,NULL);
    CloseHandle(threadHandle);
    g_IsReadThreadFinish=false;
    while (!g_IsReadThreadFinish)
    {
    Sleep(200);
    }
    i++;
    }
    }
    还有上面所说的使用互斥量,其实是你使用的不正确,你的互斥不应该是和主线程互斥,而是后台线程中的互斥。
    直接将你主线程中的waitforsingleobject和releasemutex函数去掉即可。
      

  50.   

    CreateThread是异步的.即创建个thread. 但那个thread里的代码如果只是return 0; 可能CreateThread执行下一步时,这thread就销毁了.可能thread还刚入口.. 一般的办法是阻塞thread.