Control.Invoke与消息队列

  MSDN上关于Control.Invoke的描述是:在拥有此控件的基础窗口句柄的线程上执行指定的委托。
先不考虑主是怎么找到那个拥有控件的基础窗口句柄的线程的,看看后半句,“在某个线程上执行指定的委托”,这个比较有意思。让一个正在运行的线程去执行另 一个指定的任务,这似乎不大可能。因为,任何程序都是顺序执行的,除了程序中的跳转指令外,没有任何东西可以让程序直接跑到另一个毫不相干的地址去执行。 在我们确定了线程的入口后,就没有什么东西可以干预线程的执行过程了,除非把它Drop掉。
那么,这里是怎么回事呢?微软如何让一个线程从正在执行的任务中暂停,而让它去执行另一个任务,完后再转回去继续执行原任务?显然,从技术上来说,这是一句假话。那么,Invoke函数真正做了些什么呢?我想到了PB的一个关键字:Post。
在PB中,有一个Post关键字,代码中带有Post关键字的函数调用会被封装为一个消息,发送到窗口的消息队列中。因此,该调用实际上将在当前消息处理完毕后再执行。
再了解一下使用Invoke的原因,微软的解释是:“Windows 窗体”基于本机 Win32 窗口,而 Win32 窗口从本质上而言是单元线程。STA 模型意味着可以在任何线程上创建窗口,但窗口一旦创建后就不能切换线程,并且对它的所有函数调用都必须在其创建线程上发生。STA 模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到(在其上执行)该控件的创建线程。
用时髦点的说法来解释的话,大概可以这么说:控件操作都是非线程安全的,为了保证程序的稳定性,不允许多个线程同时操作控件,所有对控件的函数调用都必须在同一个线程即其创建线程上执行。
有了这些,答案基本上就明了了:Invoke压根就不关线程什么事,它所做的工作跟PB中Post一样,把委托封装为消息,发送到窗口的消息队列中。然 后,窗体线程将处理这个消息,并执行相关的委托。虽然微软的解释里没有明确提到消息队列,但除此之外,不会有其它可能。而“在拥有控件的基础窗口句柄的线 程上执行”这前半句也同样说明了问题,因为只有这样的线程才具有消息队列。
验证一下,在程序中新建两个线程,在其中一个线程中创建一个控件,在另一个线程中使用Invoke调用控件的一个方法。代码如下:
    class TestIsInvokeImplementWithMessageQueue
    {
        public static System.Windows.Forms.Control Control;

        public delegate void OpDelegate();

        public static void ControlCreate()
        {
            Control = new System.Windows.Forms.Control();
        }

        public static void ControlInvoke()
        {
            //Exception:在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。
            Control.Invoke(new OpDelegate(Op));
        }

        public static void Op()
        {
            Console.WriteLine("This is a Message output on the thread that have the Control,but no the main thread");
        }

        public static void Test()
        {
            System.Threading.Thread Thread = new System.Threading.Thread(ControlCreate);
            Thread.Start();

            Thread = new System.Threading.Thread(ControlInvoke);
            Thread.Start();

        }
    }

此程序运行时,出现异常:在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。
此异常符合之前的推断,Invoke尝试向创建控件的线程的消息队列发送消息,但发现消息队列不存在,因此认为窗口句柄尚未创建。

参考:http://hi.baidu.com/yedaoq/blog/item/a6c1f3fcc813acf5fd037fdc.html。
(MSDN)ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs /dv_fxmclictl/html/7fe3956f-5b8f-4f78-8aae-c9eb0b28f13a.htm

posted on 2012-05-03 11:04  刺客mrchenzh  阅读(247)  评论(0编辑  收藏  举报

导航