天天看點

PostSharp - Thread Dispatching(GUI多線程)

在我們的桌面應用程式(不管是winform還是wpf)我們都必須去面對線程的dispatching。在window圖形使用者系統中像基于.net的winform或者是wpf都有一個唯一的主線程。他們是基于Win32消息循環隊列機制處理ui界面的事件(又分為事件的鑽取和隧道)、渲染。是以在一個長時間的事件進行中,我們的ui不會得到及時的更新和響應,甚至會出現假死狀态。是以在gui程式設計有這麼一條黃金規則:不要再gui主線程處理長時間的應用。對于長時間的處理,我們需要應用在異步線程中,并且通常認為最佳的實踐并不是為每一個操作建立一個線程,而是放入線程池隊列中。

注:一下代碼都分析了winform,但是貼出帶帶代碼為wpf。

       下面是響應UI按鈕事件,異步處理方式:

PostSharp - Thread Dispatching(GUI多線程)

private void okbutton_click(object sender, routedeventargs e)

{

    threadpool.queueuserworkitem(

        delegate { this.contact.save(); });

}

PostSharp - Thread Dispatching(GUI多線程)

在這裡如果我們需要操作更新UI呢?将會引出一個gui經典exception:你所操作的uI不是該線程建立的。對于這個exception我們的解決方案是:

winform:異常代理調用<code>this.begininvoke</code><code>,</code><code>wpf</code><code>這有繪畫線程:</code><code>code</code><code>如下:</code>this.dispatcher.begininvoke。

PostSharp - Thread Dispatching(GUI多線程)

private void okbutton_click( object sender, routedeventargs e )

        delegate

            {

                this.contact.save();

                this.dispatcher.begininvoke( 

                    dispatcherpriority.normal,

                    new action( () =&gt; messagebox.show( getwindow( this ), "saved!" ) ) );

            } );

PostSharp - Thread Dispatching(GUI多線程)

在上面的代碼中有很好相似之處,我們能不能簡化,使得我們的開發并不需要關心這裡的線程技術問題,沒有線程的概念化,使得我們隻需要關心我們的業務邏輯處理?在面向方向程式設計,講究縱向攔截,利用aop,我們可以很好的處理這些問題。特别是postsharp這種靜态注入方式,如微軟企業庫EL這類動态攔截方式,我們不能直接建立new對象,然而我們這裡并不能控制窗體的建立。

先看想想我們期望最終如何來這種代碼,我對代碼很吝啬,不想寫太多,寫的越少越好,就像jquery口号一樣:“write less, do more,”。我想最多加一個attribute吧,必究還是需要标示嘛。期望code如下:

PostSharp - Thread Dispatching(GUI多線程)

[onworkerthread]

    this.contact.save();

    this.showmessage( "contact saved!" );

[onguithread]

void showmessage(string message)

    messagebox.show(getwindow(this), message);

PostSharp - Thread Dispatching(GUI多線程)

在下面我們将引入兩個個attribute:onworkerthreadattribute,onguithreadattribute,實作他們。首先我們需要的是方法的攔截是以肯定是選擇methodinterceptionaspect基類。下面我們實作簡單的異常線程onworkerthreadattribute:

PostSharp - Thread Dispatching(GUI多線程)

serializable]

public class onworkerthreadattribute : methodinterceptionaspect

    public override void oninvoke( methodinterceptionargs args )

    {

        threadpool.queueuserworkitem( state =&gt; args.proceed() );

    }

PostSharp - Thread Dispatching(GUI多線程)

下面我們将實作gui線程onguithreadattribute,與上面不同的是稍微複雜一些,我們需要考慮我們的目前線程是不是主線程,如果不是那麼我們必須異步處理。wpf中我們可以用<code>dispatcher.checkaccess</code><code>,</code>winform<code>中</code><code>invokerequired</code><code>來檢測。并進行相應的操作。</code><code></code>

PostSharp - Thread Dispatching(GUI多線程)

[serializable]

public class onguithreadattribute : methodinterceptionaspect

    public dispatcherpriority priority { get; set; }

    public override void oninvoke(

        methodinterceptionargs eventargs)

        dispatcherobject dispatcherobject =

            (dispatcherobject)eventargs.instance;

        if (dispatcherobject.checkaccess())

        {

            // we are already in the gui thread. proceed.

            eventargs.proceed();

        }

        else

            // invoke the target method synchronously. 

            dispatcherobject.dispatcher.invoke(this.priority, new action(eventargs.proceed));

PostSharp - Thread Dispatching(GUI多線程)

通過上面的兩個attribute這下我們可能很簡單的操作,gui線程,使得我們并不需要關心實際如何處理更多的時間來關心我們的業務邏輯,從煩躁重複的代碼中解脫出來。

靜态注入(如postsharp)msbuild+msilinject原理淺析: