现在有多个树控件,每个树控件显示的本地某个目录下的所有文件。
在显示每个节点状态的时候,需要向服务器请求该节点的属性,然后根据不同的属性显示不同的图标状态。(有点像SVN的状态同步)
网络请求只能有一个线程,所以我设计了一个队列,把要请求状态的子节点依次排入队列。
每次子节点向服务器请求完毕后删除出队列,并根据返回的属性,设置树节点的状态。
现在的问题如下:
1.队列中某个树节点在向服务器请求状态后,如果这个节点被删除了,则修改节点状态时该节点Handle已经无效,会导致崩溃。而请求线程并不知道树控件发生了什么。如何解决?
2.客户端关闭时,如果队列中仍有节点需要同步,这个时候如何设计“等待”的机制,让队列处理完同步再安全退出呢?
我在设计的时候,请求线程访问树控件会导致代码死锁,百思不得其解如果有描述不清楚的地方请大家指出。
望有经验的前辈指点

解决方案 »

  1.   

    1.队列中某个树节点在向服务器请求状态后,如果这个节点被删除了,则修改节点状态时该节点Handle已经无效,会导致崩溃。而请求线程并不知道树控件发生了什么。如何解决?你线程不做修改treectrl的代码,线程只管请求数据与接收数据,数据接收后处理不在线程里,而是线程发送消息给treectrl所在的父窗口处理(也就是根据数据修改图标)。2.客户端关闭时,如果队列中仍有节点需要同步,这个时候如何设计“等待”的机制,让队列处理完同步再安全退出呢?如果按我上面线程不做修改treectrl的代码,而是通过发送消息到treectrl的父窗口去处理的话,这个问题就不是问题了,要退出时,直接线程退出就行了,不过发送消息要用SendMessage这个函数,使得线程在最后一个消息发送出去后,退出,这样就不会有问题。
      

  2.   

    1、更新控件数据最好放在控件所属线程中处理。可以利用SetItemData保存节点的请求信息结构指针。
    2、更新控件数据最终是通过SendMessage给控件发消息来实现的,当目标控件不属于当前线程时,SendMessage会等待控件所属线程来处理消息,消息处理完后才会返回。在你的程序中,工作线程给主线程的控件SendMessage,等待主线程处理;而主线程在等待工作线程结束,没有处理消息,工作线程会一直停在SendMessage里面,所以死锁。可以改成关闭程序时通过定时检查工作线程是否已结束,然后再退出主线程。
      

  3.   

    谢谢大家,问题基本解决了!
    分享思路如下:
    zxdyu2009说的很对,线程只管请求数据与接收数据,数据接收后处理不在线程里,而是由相应的处理逻辑去处理。
    cnzdgs说的关闭程序时通过定时检查工作线程是否已结束,然后再退出主线程是很正确。但关键在于等待过程中不能让小西队列阻塞,因此在轮询时必须处理消息,解决思路如下:
            while (TRUE == CSynchronizeSvn::Single().GetBusyState())
            {            
                // Process all process messages
                MSG msg;
                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }   
            }
    这样用户不会有卡的感觉。
    另外,在树需要重建(这时候树的所有节点都将被删除)的时候,需要通过禁用UI的方式阻止用户重复push刷新任务,这样就不会出现刷新了不存在的节点的问题。