用全局变量控制
BOOL gFlag=FALSE;
OnTimer()
{
  gFlag=TRUE;
  ...
  gFlag=FALSE;
}
当gFlag为TRUE时其他部分不执行

解决方案 »

  1.   

    EnterCriticalSection
    LeaveCriticalSection
    CEvent  event;
    WaiteForSingleObject()
    event.SetEvent
      

  2.   

    criticalsection 不行,我用的就是这种方法
    cevent我试试看
      

  3.   

    我想你是你的代码的问题,理由:1、WM_TIMER 消息处理和其他消息处理道理是一样的,除了对话框可以让消息循环继续外,其他情况是不会从新进入的。所以,当你处理其他消息的时候,OnTimer 是不会执行的,包括 OnTimer 本身也不会从新进入,不信你可以 SetTimer( 1000, NULL ); 在 OnTimer 里用 Sleep( 2000 ) 看看效果。2、要知道线程是操作系统分配的单位,他的执行顺序才是真正的无序的。你所提到的线程同步的信号量,互斥量还不能够解决问题,这就怪了,如果这个也不能够解决问题,那说明问题在你的代码了。建议你再检查你的代码的逻辑。
      

  4.   

    朋友,你这样互斥方法不对. 换句话说,你这样能互斥的话.操作系统干么要费那么大劲实现PV操作干啥.(1) 为什么不对,分析如下:
       Thread1 if(!gFlag)
    {
    //delete something1 //step 1
    //delete something2 //step 3
    }Thread2BOOL gFlag=FALSE;
    OnTimer()
    {
      gFlag=TRUE;  //step 2
      ...          //step 4     
      gFlag=FALSE;
    }执行顺序如上,则step4出错. (2) 所以说,怎样理解互斥,简单地说,就是把你要做的东西全部做完,在你做完之前,另一块互斥区不能执行.(3) 用临界区互斥
    CCriticalSection gFlagThread1
    gFlag.Lock()
    ...
    gFlag.Unlock()
    Thread2
    gFlag.Lock()
    //delete something
    gFlag.Unlock()
      

  5.   

    1. OnTimer是能够重入的, 你在OnTimer中加个MessageBox就知道了。
    2. 我程序只有一个函数释放与此相关内存,我对它已经作了同步处理。
    3. 我所有的代码在同一个线程之中。
      

  6.   

    致 freelybird(阿愚):我就是按你的第三种方法作的,你指出的那种错误做法是别人回复的
      

  7.   

    to 回复人: freelybird(阿愚) (  ) 信誉:100  2002-04-28 10:05:00  得分:0  
    没错,用普通变量来互斥是肯定不行的。
    to 回复人: localvar(localvar) (  ) 信誉:100 我说过了,对话框是可以让消息重入的。当然也包括 messagebox
    不管是否重入,如果使用了 线程互斥机制,就一定不会出现问题。我建议你仔细查一查你的申请内存和释放内存,以及使用内存的代码。看看是否有使用内存越界等等。
      

  8.   

    /*******我没有写过 dde 程序,但我看了你的代码,发现一个可能存在的问题:*****/OnTimer( ... )
    ...
    ...
    if(m_bConnected)
    {
    HDDEDATA hData = NULL;
    DWORD dwSize = 0;
    BYTE buf[64];  /****注意 大小只有 64 bytes, 我的意见是修改为 buf[65] ********/
    SENDPACKITEM* pItem = (SENDPACKITEM*)(m_pSendBuf + sizeof(SENDPACKHEADER));
    CString strText;
    //我的测试环境中m_wPointCount = 500
    for(WORD i=0; i<m_wPointCount; i++)
    {
    hData = DdeClientTransaction(NULL, 0, m_hConv, m_pPointInfo[i].hszName, 1, XTYP_REQUEST, TIME_OUT, NULL);
    if(hData == NULL)
    continue;
    dwSize = DdeGetData(hData, buf, 64, 0); 
    buf[dwSize] = '\0'; /***** 注意前面定义,如果读出来刚好是 dwSize == 64 byte 那么,这个代码就可能是问题**********//********* 关于 DdeGetData  msdn 上是这么说的 Return Values
    If the pDst parameter points to a buffer, the return value is the size, in bytes, of the memory object associated with the data handle or the size specified in the cbMax parameter, whichever is lower. If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object associated with the data handle. 
    ***********/
      

  9.   

    to scklotz(晓春):
    我知道这个问题,如果你也看了我其他部分的代码的话,你会发现我处理缓冲区是非常小心的。程序中有少数几个地方直接指定了缓冲区的大小,但是在这些地方,我可以保证在最终的运行环境中缓冲区不会溢出。在用excel进行测试的时候,我取过来的数据也仅有几个字节而已,所以不会是这出错。问题我想我已经找到了,他出在对DdeClientTransaction的调用上, msdn上说以同步方式对它的调用不会阻止程序对其他用户输入的响应。也就是说对它的调用过程,和显示一个对话框是类似的。很有可能是在对它进行调用时,我删除缓冲区的代码执行了,最终导致出错。至于线程同步机制不起作用,我想是不是因为,这些机制只能用于不同线程之间,而在同一个线程上使用无效呢?
      

  10.   

    to scklotz(晓春):我是通过局域网上网的,qq被封了。所以不能和你用qq交流。
      

  11.   


    还有一段代码也有问题:OnTimer( ... )
    ...
    ...
    Send(sizeof(SENDPACKHEADER) + sizeof(SENDPACKITEM)*m_wPointCount);
    SetTimer(IDT_TIMER, 1000, NULL);
    }// m_critical_section.Unlock(); ShowStatus();
    CDialog::OnTimer(nIDEvent);

    如果 Send 调用失败,会触发: CloseAll(), 消息框
    再之后,SetTimer ( CloseAll 调用过 KillTimer )
    进入 OnTimer 代码
    而此时, CloseAll 已被调用。
    实际上,你必须检查 Send 的返回值。
      

  12.   

    还有 DDE 的回调函数
    触发消息处理函数:LONG CJhDlg::OnParterClosed(WPARAM, LPARAM)
    {
    CloseAll();
    CString str((LPTSTR)IDS_DDE_PARTER_CLOSED);
    MessageBox(str, NULL, MB_OK|MB_ICONINFORMATION);
    return 0;
    }也是间接除法 CloseAll
    照你所说的,那问题可能就是这样的:DdeDdeClientTransaction 过程中,可能调用了 DdeCallback
    由于 DdeDdeClientTransaction 并不阻塞消息循环,
    所以 消息处理被调度 OnParterClosed
    然后是 CloseAll这样就可能出现问题了。你可以在 OnParterClosed 加入一条 TRACE 看看效果如何。
      

  13.   

    还有 DDE 的回调函数
    触发消息处理函数:LONG CJhDlg::OnParterClosed(WPARAM, LPARAM)
    {
    CloseAll();
    CString str((LPTSTR)IDS_DDE_PARTER_CLOSED);
    MessageBox(str, NULL, MB_OK|MB_ICONINFORMATION);
    return 0;
    }也是间接除法 CloseAll
    照你所说的,那问题可能就是这样的:DdeDdeClientTransaction 过程中,可能调用了 DdeCallback
    由于 DdeDdeClientTransaction 并不阻塞消息循环,
    所以 消息处理被调度 OnParterClosed
    然后是 CloseAll这样就可能出现问题了。你可以在 OnParterClosed 加入一条 TRACE 看看效果如何。
      

  14.   

    to scklotz(晓春):这确实是一个问题,我没有想到。
    而且他还会引起一个问题,如果我的线程同步代码起作用的话,会发生死锁。
    谢谢。
    但是这不是引起上面错误的原因,因为Send失败,会弹出消息框(或,如果有同步机制的话,会发生死锁),而实际上出错时并没有出现这种情况.
      

  15.   

    你说得很对,我一直以为我写的程序bug很少,没想到你找出了这么多。现在错误的原因基本上确定了,就是出在DdeClientTransaction的调用上。能帮我想个解决的办法吗?
    虽然没有从资料上证实,但是线程同步机制在这里好像不起作用。不知你对此有什么看法?
    另:你距一星会员还差多少分?如果不多的话我就给你凑够了吧 :)
      

  16.   

    你说的没有错,确实是这样的,看来是我犯了一个错误 :(
    CCriticalSection 在单线程里没有效果,返回到原始时代,还是用变量来控制吧,
    用成员变量或者局部静态变量
    例如如下的代码回工作得很好:OnTimer( ... )... ... static b = false; if( ! b ) {
    b = true;
    time_t t = time(NULL);
    TRACE( "===%d start===\n", t );
    MessageBox( "var timer" );
    TRACE( "===%d end  ===\n", t );
    b = false;
    }... ...
    相信你应该知道怎么做。
      

  17.   

    根据一个变量,来控制各个消息处理函数之间的同步。
    而不是根据线程同步机制。在 MessageBox 之类的半阻塞函数中,
    我认为有点类试于递归调用,变量之间的赋值与读取不会受到
    类似多线程那样的影响。
      

  18.   

    好了就到这吧,给分了。虽然一般情况下不能用变量进行互斥,但在这里是可以的(只适用于此程序,并不适用于所有的timer事件处理),因为我的两部分程序不可能同时访问那个变量(我的删除代码运行时,OnTimer正在DdeClientTransaction中转悠那)。我通过此问题得到的知识:
    1. OnTimer一般情况下不能重入,但在有对话框或某些特殊函数时,可以重入。
    2.线程同步机制只适用于多线程,对单线程无效。
      

  19.   

    虽然我认为AloneWolf回答问题时没有想那么多,但考虑到最后解决方法是他的方法,所以...
      

  20.   

    我补充一点:about: 2.线程同步机制只适用于多线程,对单线程无效。这个道不完全是的,你可以试试 CMutex 和 CEventabout: 变量之间的赋值与读取会不会受到类似多线程那样的影响,我不太清楚我举例说明:当多个线程访问一个变量时候(读/写),由于线程运行的时间上不确定,
    例如,线程1 
    mov var -> register
    之后被操作系统中断线程2
    mov register -> var
    之后被操作系统中断线程1
    cmp register xxx这个时候,线程1 得到的值就是有问题的值。
      

  21.   

    CMutex也不能用于单线程,我认为他们不能用于单线程是因为可能在一个线程中出现以下代码:CMutex mutex;void func2()
    {
       mutex1.Lock();
       ...
       mutex.Unlock();
    }void func1()
    {
       mutex1.Lock();
       func2();   //如果单线程可行的话,这里将发生死锁
       mutex.Unlock();
    }