我的程序有三个线程:
1.主线程(线程1)
2.接收网络数据(线程2)
3.随时间变化修改处理数据的线程(线程3)线程2,每接收到一段完整的数据,就进入临界区修改相应的数据,并修改窗口的显示内容,完毕之后离开临界区。
线程3,每次循环的开头都进入临界区,循环的末尾都离开临界区,循环体根据时间修改处理数据,若数据有变化,则修改窗口显示的内容。
线程1,响应用户对窗口进行的操作。有些操作也要进入临界区。在测试过程中,线程2和线程3比较复杂,但是这两个线程确实没有出现相互死锁的情况。但是,有些时候对窗口进行操作,需要进入临界区的话,就有几率导致窗口无响应,似乎死锁了。今天我调试了一天,发现只要线程3的循环体执行时间长一点就会导致窗口无响应。线程3的循环体中,其中一组数据发生改变时,就要重新在列表中显示一遍数据(大概30多行,每行5列,其实花费时间不会超过100毫秒),此时对窗口进行操作,响应窗口消息时就有可能导致窗口无响应。而我如果把所有列表控件的SetItem函数都删除了,那就不会出现这种情况。我直接把重新显示数据的函数换成Sleep的话,1毫秒不会出问题,100毫秒每次操作都出问题。操作对应的消息响应函数极为简单,只有一个出口,所以可以确定三个线程中的进入(EnterCriticalSection)和退出(LeaveCriticalSection)临界区是成对出现的。按理说,每组进入临界区 和 退出临界区之间的程序段执行时间都不超过1秒钟,是不可能导致窗口长时间无响应的嘛,但是为啥线程3的循环体执行时间太长,在窗口上进行操作就会导致窗口无响应呢?请问,导致窗口无响应的原因还有没有其他什么原因?

解决方案 »

  1.   

    首先明确一点,你只使用了一把锁吧?如果是一把锁那就不会是线程内死锁。另外按你说EnterCriticalSection和LeaveCriticalSection确定是成对出现,并且保证是会执行到的话那么应该不存在死锁问题。你调试一下,看看几个线程都在干什么
      

  2.   

    因为是时不时出现的问题,所以我用写文件的方式来跟踪代码执行到何处无响应。
    我在要跟踪的程序段前后分别把“+X”和“-X”写入文件(X是成对变化的)。发现似乎一直在重新显示数据那里循环着,极少数时候+X 和 -X是成对的。多数时候最后一个跟踪的标记是+X,并且都是显示数据里面的。而且,窗口无响应的时候,进程CPU利用率为16%左右,不像是临界区死锁的问题。
      

  3.   

    后来我以为是列表控件自绘的问题。我就把控件类修改成原始的CListCtrl,同样也会出现问题。
      

  4.   

    对UI的内容更新,请确保是在主线程1上进行,如果没有,就SendMessage或者PostMessage出来。
    其他线程,检查下临界区内容的保护范围,尽量缩小范围。
      

  5.   


    就是线程3和线程1之间出问题了。线程2和线程3之间不会出问题。
    显示数据的时候也要读取临界区中的数据的。
    原本我也使用发消息的方式来更新显示数据的,但是有一个隐患,若消息太多,处理消息不及时,那就可能导致有些消息没有被处理,导致显示的和实际的数据不一致。比如,点开窗口菜单的时候,消息处理线程就暂停了。-----------------------------我主要是想知道为什么我的程序会导致无响应。
    在我看来,没有死锁的情况下,无论进入临界区和离开临界区之间的程序段执行所花费时间有多长,最多也就在这段时间之内,窗口无响应,离开临界区之后窗口应该恢复响应才对嘛。应该最多也就是一卡一卡的,而不是一直无响应下去。
    而如果有死锁的情况,那最终进程的CPU利用率应该是0%才对。
      

  6.   

    如果消息过多,很可能是你刷新的速度太快,其实你根本没有必要做这么高的刷新,眼睛看得过来吗?
    在消息处理里面加个刷新锁,用PostMessage再试试
      

  7.   

    我刚刚调试了一下,确定了线程的行为,发现更诡异了。
    双击列表控件的响应函数,在申请进入临界区那里暂停了,原因是有别的线程占用临界区,这很正常。(每次都这样)。然后我修改了代码,把程序执行到何处的标志写入文件。
    this->m_ep.test_file.Write("E",1);
    EnterCriticalSection(&this->m_ep.CSS_Info);
    this->m_ep.test_file.Write("F",1); INT_PTR count=.....(保密);
    this->调整列表控件列数(lc,count);
    this->m_ep.test_file.Write("G\r\n",3);
    for(INT_PTR i=0;i<count;i++)
    {
    this->m_ep.test_file.Write(" 1",2);
    XXX *fn=......(保密);
    this->m_ep.test_file.Write("2",1);
    int k=0;
    if(fn)
    {

    {
    this->m_ep.test_file.Write("3",1);

    CString str;
    str.Format("%d",i+1);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,fn->name,0,0,0,0);
    str.Format("%d",fn->id);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);
    str.Format("%d,%d",fn->x,fn->y);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);

    this->m_ep.test_file.Write("4",1);
    }
    }
    else
    {
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    }
    this->m_ep.test_file.Write("5\r\n",3);
    }
    this->m_ep.test_file.Write("H",1);
    LeaveCriticalSection(&this->m_ep.CSS_Info);
    this->m_ep.test_file.Write("I\r\n",3);
    窗口无响应后,文件中的内容:
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    HI
    EFG
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    HI
    EFG
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    HI
    EFG
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    HI
    EFG
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    12345
    123
    看情况是程序在3 4 之间卡住了,很莫名其妙啊。这一段没有上锁呢,也没有抛出异常。双击事件也不会导致线程被挂起。为啥双击后就不执行了呢。
      

  8.   

    我今早又调试了,情况更诡异了。
    双击列表控件,响应消息函数中,申请进入临界区时,因为临界区被占用,所以暂停。(这很正常)我修改了代码,把程序运行到何处的标志写入文件:
    this->m_ep.test_file.Write("E",1);
    EnterCriticalSection(&this->m_ep.CSS_Info);
    this->m_ep.test_file.Write("F",1); INT_PTR count=.....(保密);
    this->调整列表控件列数(lc,count);
    this->m_ep.test_file.Write("G\r\n",3);
    for(INT_PTR i=0;i<count;i++)
    {
    this->m_ep.test_file.Write(" 1",2);
    XXX *fn=......(保密);
    this->m_ep.test_file.Write("2",1);
    int k=0;
    if(fn)
    {

    {
    this->m_ep.test_file.Write("3",1);

    CString str;
    str.Format("%d",i+1);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,fn->name,0,0,0,0);
    str.Format("%d",fn->id);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);
    str.Format("%d,%d",fn->x,fn->y);
    lc.SetItem(i,k++,LVIF_TEXT,str,0,0,0,0);

    this->m_ep.test_file.Write("4",1);
    }
    }
    else
    {
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    lc.SetItem(i,k++,LVIF_TEXT,"",0,0,0,0);
    }
    this->m_ep.test_file.Write("5\r\n",3);
    }
    this->m_ep.test_file.Write("H",1);
    LeaveCriticalSection(&this->m_ep.CSS_Info);
    this->m_ep.test_file.Write("I\r\n",3);窗口无响应之后,文件中内容为:
    EFG
    HI
    EFG
    HI
    EFG
    HI
    //省略一段,数据未到达,循环体不执行
    EFG
    12345
    12345
    12345
    //省略一段,循环体
    12345
    12345
    HI
    //省略一段
    EFG
    12345
    12345
    12345
    //省略一段
    12345
    12345
    12345
    12345
    123
    //这里卡住了,真是莫名其妙,3和4之间没有任何进入临界区的锁,也没有抛出异常,双击事件也不会导致线程被挂起,实际上没有挂起此线程的操作。为啥程序就在这停了呢?