请僵哥赐教!
据我所知,在初始化Application时,VCL会为主线程创建一个消息队列,这样的话,凡是在主线程内创建的对象(这里的对象是指有Handle的对象)均可享用该消息队列!
问题:
1.如果在子线程中创建的对象,是不是还要手工为该线程创建一个消息队列(因为我想做一个线程内的异步处理(非阻塞处理))?这样子线程内创建的对象就可以响应该对象的消息了?但在VCL封装的线程类中,并没有看到线程的窗口函数与窗口句柄(只看到了线程的Handle),VCL如何将消息转发到窗口函数中的?系统为什么不为子线程自动创建一个消息队列?
2.利用AllocateHWnd是可以为线程分配一个窗口句柄,也就可以用SendMessage或Postmessage了,但这个是不是一定要结合消息循环来做,否则是不是实现不了非阻塞线程?另外好像有个PostThreadMessage,如果线程无消息队列,这个函数是不是就没用?
3.VCL的控件中中有一部分Control是无Handle的,那它们是怎么响应消息的?难道它是必须依赖于有窗口的控件,让这些控件顺便来提示它们?

解决方案 »

  1.   

    嘿嘿,我来抢Unsigned的分.>>>"如果在子线程中创建的对象,是不是还要手工为该线程创建一个消息队列(因为我想做一个线程内的异步处理(非阻塞处理))?"
    消息队是操作系统维护的,并以线程进行区分,无需你来创建
    >>>这样子线程内创建的对象就可以响应该对象的消息了?
    要响应消息,需要实现从消息队取消息以及派发消息的循环.系统只是实现消息队,从消息队中取消息需要自己实现.
    即在线程中需要有类似以下代码
    while GetMessage do
    begin
      TranslateMessage;
      DispatchMessage;
    end;
    而主线程中你不需要这么做的原因是VCL帮你实现了改代码.>>>但在VCL封装的线程类中,并没有看到线程的窗口函数与窗口句柄(只看到了线程的Handle),VCL如何将消息转发到窗口函数中的?
    线程于窗口没有必然联系,线程可以只是以段处理逻辑的代码.就上面以一条已经告诉你了,线程中,VCL不负责消息转发,你需要自己负责.>>>系统为什么不为子线程自动创建一个消息队列? 
    不是系统没创建,而是你没去取而已.
    >>>2.利用AllocateHWnd是可以为线程分配一个窗口句柄,也就可以用SendMessage或Postmessage了,但这个是不是一定要结合消息循环来做,否则是不是实现不了非阻塞线程?另外好像有个PostThreadMessage,如果线程无消息队列,这个函数是不是就没用? 
    这个你参考我上面的说明.>>>3.VCL的控件中中有一部分Control是无Handle的,那它们是怎么响应消息的?难道它是必须依赖于有窗口的控件,让这些控件顺便来提示它们?
    你的怀疑是正确的,它们就是靠父窗口来转发消息的.
      

  2.   

    线程内的异步处理,并不一定要通过消息,实际上通过消息也只能由PostThreadMessage/PostMessage(不建议使用这个函数),来发送一个异步处理通知,具体的数据传递仍然需要通过相应的机制进行传递,并且由于是跨线程,所以仍然逃不开需要进行临界区保护。更为重要的是,消息队列是有限的(默认10K个),当线程来不及处理而导致积压之后,后续投递的消息将会失败。个人建议如果线程并不需要处理如窗口消息等,仅是既定的工作内容。那么就使用一个List进行传递,然后通过线程描述来达到目的。并且这样子扩充性就好很多,如果是通过消息的话,那么你业务就得投递到既定的线程窗口当中去,要实现线程池,那业务的分派就麻烦很多,如果使用List的话,那么就可以通过多个线程共同处理同一个List当中的内容而更好的发挥线程池的效用。实际上在Windows 2000之后,几乎几有版本的系统都可以使用完成端口,那么就可以做一个基于完成端口的消息队列,通过PostQueuedCompletionStatus投递业务节点,然后处理线程则通过GetQueuedCompletionStatus来读取业务节点并进行处理。实现线程池就简单得多了。
      

  3.   

    好像都说完了
    补充一点吧当你在程序中第一次创建一个子线程时, VCL将会从主线程环境中创建和维护一个隐含的线程窗口。
    此窗口唯一的目的是把通过Synchronize()调用的方法排队。
      

  4.   

    理解Windows消息机制(转)  
       
      Windows系统是一个消息驱动的OS,什么是消息呢?我很难说得清楚,也很难下一个定义(谁在嘘我),我下面从不同的几个方面讲解一下,希望大家看了后有一点了解。    
       
      1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。    
       
      2、谁将收到消息:一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。    
       
      3、未处理的消息到那里去了:M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用 Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。    
       
      4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。  
       
      5、示例:下面有一段伪代码演示如何在窗口过程中处理消息    
       
      LONG   yourWndProc(HWND   hWnd,UINT   uMessageType,WPARAM   wP,LPARAM)  
      {  
      switch(uMessageType)  
      {//使用SWITCH语句将各种消息分开  
      case(WM_PAINT):  
      doYourWindow(...);//在窗口需要重新绘制时进行输出  
      break;  
      case(WM_LBUTTONDOWN):  
      doYourWork(...);//在鼠标左键被按下时进行处理  
      break;  
      default:  
      callDefaultWndProc(...);//对于其它情况就让系统自己处理  
      break;  
      }  
      }  
       
       
      接下来谈谈什么是消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。下面的伪代码演示了消息循环的用法:    
       
      while(1)  
      {  
      id=getMessage(...);  
      if(id   ==   quit)  
      break;  
      translateMessage(...);  
      }  
       
      当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。   图示消息投递模式    
       
      在16位的系统中系统中只有一个消息队列,所以系统必须等待当前任务处理消息后才可以发送下一消息到相应程序,如果一个程序陷如死循环或是耗时操作时系统就会得不到控制权。这种多任务系统也就称为协同式的多任务系统。Windows3.X就是这种系统。  
       
      而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务系统就称为抢先式的多任务系统。Windows95/NT就是这种系统。    
        
      

  5.   

    http://topic.csdn.net/t/20010805/17/224654.html