有两个线程A和B,由于某种原因,打算使用Suspend和Resume来实现两个线程的同步。\\
设置一个全局标志位g_bFlag,和一个全局的CRITICAL_SECTION,A线程若检测到该g_bFlag为True,则Resume线程B,若该g_bFlag为Fals,则Suspend自身,等待B线程来Resume它。同样,B也进行这样的操作。开始线程跑的不错,但是经过若干次以后,A和B线程都会Suspend。\\
ps:对g_bFlag的访问和修改都使用了CRITICAL_SECTION来包含,并且将g_bFlag申明成了volatile bool。为什么会出线这样的情况呢?

解决方案 »

  1.   

    是怎么保证线程A suspend的时候,线程B不是suspend的?假设g_bflag为false的时候,两个线程先后访问它呢
      

  2.   

    对g_bFlag的访问和修改都使用了CRITICAL_SECTION这里好像有问题,你达到的目的只是,读g_bFlag时只有一个线程,写g_bFlag时也只有一个线程,可是读和写之间,还是有可能并发。
      

  3.   

    临界区:CRITICAL_SECTION只起保护做用,不能达到同步效果。
    用对象事件,或信号量等;方法很多。
      

  4.   

    不要使用挂起和恢复操作,应该使用wait操作
      

  5.   

    看来是同步没有处理好,需要看代码。另外提一下,如果你的两个线程不同时运行,应该用Fiber更合适,参考MSDN中CreateFiber的说明。
      

  6.   

    ThreadA(...)
    {
        ....
        bool bStatu = g_bFlag;
        EnterCriticalSection(..);
        g_bFlag ^= TRUE;
        LeaveCriticalSection(...);    if( bStatu )
        {
            Resume(ThreadB);
        }
        else
        {
            Suspend(Me);        
        }
        ...
    }请问LZ是这样的吗?记住:顺序一定不能搞反了。另外为什么要内部定义一个变量来保存你的全局变量,自己想一下吧!初步估计你是在挂起自己之前,没有释放临界区(即是先Suspend,后LeaveCriticalSection),导致另一个线程无法修改全局变量,从而也无法唤醒另一个线程。
      

  7.   

    ThreadA:
    EnterCriticalSection(&g_CS);
    if (!g_bFlag)
    {
       m_thread_statue = suspend;
       ::LeaveCriticalSection(&g_CS);
       SuspendThread(m_hThread);
       m_thread_statue = running;
    }
    else
    {
      g_bFlag = true;
      ::LeaveCriticalSection(g_CS);
      ResumeThread(pThreadB->m_hThread);
    }ThreadB的代码和ThreadA的代码一致。
    我解释一下为什么不打算使用同步对象。是由于一旦WaitSingleObject(hEvent,500),在这500ms里面,OS不会释放对Thread的占用,而且CPU的占用率也较高,使用SuspendThread会使OS立刻切换线程。Fiber没有用过,所以没有使用Fiber。
      

  8.   

    偷偷问问vcPlayer,如何在论坛中贴代码呢?
      

  9.   

    [code = {2}]
    EnterCriticalSection(&g_CS); 
    if (!g_bFlag) 

       m_thread_statue = suspend; 
       ::LeaveCriticalSection(&g_CS); 
       SuspendThread(m_hThread); 
       m_thread_statue = running; 

    else 

      g_bFlag = true; 
      ::LeaveCriticalSection(g_CS); 
      ResumeThread(pThreadB->m_hThread); 

    [/code]
      

  10.   

    测试:
    [code = {0}] 
    EnterCriticalSection(&g_CS);  
    if (!g_bFlag)  
    {  
       m_thread_statue = suspend;  
       ::LeaveCriticalSection(&g_CS);  
       SuspendThread(m_hThread);  
       m_thread_statue = running;  
    }  
    else  
    {  
      g_bFlag = true;  
      ::LeaveCriticalSection(g_CS);  
      ResumeThread(pThreadB->m_hThread);  
    }  
    [/code]
      

  11.   

    ThreadA: EnterCriticalSection(&g_CS); 
    if (!g_bFlag) 

       // 这里假的时候,为什么不设为真让另一线程来唤醒自己?g_bFlag = TRUE;
       m_thread_statue = suspend; 
       ::LeaveCriticalSection(&g_CS); 
       SuspendThread(m_hThread);      // 是否应与下面一句交换次序?
        m_thread_statue = running;

    else 

      g_bFlag = true; // 已经为TRUE了,这里为什么还要设为TRUE?是否应该为FALSE? g_bFlag = FALSE;
      ::LeaveCriticalSection(g_CS); 
      ResumeThread(pThreadB->m_hThread); 
    } 贴代码先选中你的代码,然后点击编辑框上的带“#”的图标,选择你的代码语言就可以了。或者在你的代码前后用..括起来。
      

  12.   

    g_bFlag是在什么地方修改的?上面代码中不会修改g_bFlag,如果g_bFlag是false则两个线程就都suspaend了。
    WaitSingleObject就是放弃CPU时间,怎么可能导致CPU使用率过高呢?
    如果多个任务同一时间只有一个在运行,用Fiber是最合适的了,Fiber就是为这种情况设计的。
      

  13.   

    写错了,应该是:
    EnterCriticalSection(&g_CS); 
    if (!g_bFlag) 

       g_bFlag = true;
       m_thread_statue = suspend; 
       ::LeaveCriticalSection(&g_CS); 
       SuspendThread(m_hThread);      // 是否应与下面一句交换次序?
        m_thread_statue = running;

    else 

      g_bFlag = false;
      ::LeaveCriticalSection(g_CS); 
      ResumeThread(pThreadB->m_hThread); 
      

  14.   

    13楼的:
    “WaitSingleObject就是放弃CPU时间”,对于这点我不甚理解,因为没有文档可循。我只知道在Event被Trigger的情况下,等待的线程可以获得CPU的调度机会。
    14楼的,Suspend都是自己suspend自己,而不是由外界进行Suspend操作,另外在自己suspend自己之前都会有LeaveCriticalSection的操作。
      

  15.   

    这段代码需要看初始条件是怎么样?我觉得吧,lz最好把g_bFlag的一些状态在output输出来看看
      

  16.   

    当Wait的时候线程进入休眠,而不是挂起(两个都不占用CPU),只有当wait的信号激活或者超时的时候,系统才会重新唤醒线程继续执行。
      

  17.   

    楼上的,我在执行ResumeThread的时候,对Return出来的值进行了判断。
    ps:我已经将Flag都打印出来了,打印出来的结果都是一致的……郁闷。
      

  18.   

    问题出在这里:
    EnterCriticalSection(&g_CS); 
    if (!g_bFlag) 

       g_bFlag = true;
       m_thread_statue = suspend; 
       ::LeaveCriticalSection(&g_CS); 
       SuspendThread(m_hThread);     
        m_thread_statue = running;

    else 

      g_bFlag = false;
      ::LeaveCriticalSection(g_CS); 
      ResumeThread(pThreadB->m_hThread); //你怎么知道每个线程判断当g_bFlag为true时,都要终止线程B呢?
    }1.假设一开始线程A开始,线程B暂停,那么,当线程A运行到
    ResumeThread(pThreadB->m_hThread); 
    时,A与B线程同时开始,但g_bFlag为false,A的下一循环会进入到
    EnterCriticalSection,而B线程也会进入到EnterCriticalSection,究竟哪一个先进入EnterCriticalSection没有定数,
    2.万一线程A先入EnterCriticalSection,那么线程B被暂停。
    此时线程A执行第一个if条件,到语句
     m_thread_statue = running
    之后:
    g_bFlag=true,A线程暂停,
    3.B线程因为A线程运行到LeaveCriticalSection而继续。
    线程B根据g_bFlag条件,执行语句第二条if语句块。重新把自己启动。
    4.当线程B再次进入到EnterCriticalSection之后,g_Flag为false,执行到SuspendThread就把自己给暂停了,
    结果两个线程都被暂停。设置两个线程句柄与两个线程过程,SuspendThread与ResumeThread要操作的对象要区分开来。
    线程A,暂停线程A,启动线程B
    线程B,暂停线程B,启动线程A
      

  19.   

    楼上的,你的说法有问题哈:
    1.EnterCriticalSection的时候只会有一个Thread进入,另外一个Thread会等前一个线程LeaveCriticalSection才进入;
    2.进入EnterCriticalSection的线程会先看看flag,如果flag不为true,那么就suspend自己,直到另外一个Thread Resume自己。
    3.B任何线程Suspend自己之前都保证自身的状态被记录下来
      

  20.   

    楼主说的对,但要想一想,在第一步之后,A线程会把B线程开启,B线程一开始会运行到EnterCriticalSection,A线程因为循环再次运行到EnterCriticalSection.确实,EnterCriticalSection的时候只会有一个Thread进入,但这时,是A线程先到EnterCriticalSection,还是B线程先到,无法确定.如果A线程先运行EnterCriticalSection,那么B线程即时无法启动,直到A线程运行到LeaveCriticalSection为止.第一步之后,究竟谁还能运行,存在着资源竞争.
    你是否真的为每个线程设置了各自的状态,我只看到一个g_bFlag,这个变量好像是全局的.你是否为每个线程区分地定义了各自的状态.
      

  21.   

    // CChildFrame 诊断#ifdef _DEBUG
    void CProjectFrame::AssertValid() const
    {
    CMDIChildWnd::AssertValid();
    }
      

  22.   

    最后改用WaitForSingleObject()解决问题。WaitForSingleObject的思路与上面的编码类似。郁闷呀。
      

  23.   

    CRITICAL_SECTION很容易造成死锁的。对于多线程读写文件,可以用OVERLAPPED I/O的方式读写文件,具体参看CreateFile文档内容中关于OVERLAPPED的讨论
      

  24.   

    1,楼主还没有看出为何原来方式就是锁死的话,我建议你不要放弃再仔细想想。找张纸把运行路线的所有组合画一画,必有一种是互锁了的。画一画就知道。我也经常像你一样,宁愿在脑子里想来想去想得头疼,也懒得动笔画一画。2,多线程的同步问题需要特别的小心才行。我的方法一般是能避免同步操作就避免,能用简单的同步对象就不用复杂的。能公认的方法就不用自创的。你的这种方法我搞研发5年了头一次听说。我觉得应当佩服你的勇气,不要像我一样墨守成规。3,如果还在认为WaitForXXX会占用CPU,或者尚未使用过Fiber,则真诚的建议你暂时放下键盘,拿起书去学习学习。去买一本侯杰老师译著的《Win32多线程程序设计》看看吧。