2013-08-01 120 views
0

我有MVP應用程序C#,.NET 4,WinForms。它使用Bridge類,通過NamedPipe與第三方應用程序進行通信。 命令流程如下:查看→演示器→管理器→橋接器→客戶端 然後按相反的順序返回。視圖準備好多任務處理。我在Manager中通過上升事件來分割反向鏈,但結果不起作用。哪裏打破任務鏈,ContinueWith,鎖

// View class 
public void AccountInfo_Clicked() { presenter.RequestAccountInfo(); } 

public void UpdateAccountInfo(AccountInfo info) 
{ 
    if (pnlInfo.InvokeRequired) 
     pnlInfo.BeginInvoke(new InfoDelegate(UpdateAccountInfo), new object[] {info}); 
    else 
     pnlInfo.Update(info); 
} 

// Presenter class 
public void RequestAccountInfo() { manager.RequestAccountInfo(); } 

private void Manager_AccountInfoUpdated(object sender, AccountInfoEventArgs e) 
{ 
    view.UpdateAccountInfo(e.AccountInfo); 
} 

// Manager class 
public void RequestAccountInfo() 
{ 
    AccountInfo accountInfo = bridge.GetAccountInfo(); 
    OnAccountInfoUpdated(new AccountInfoEventArgs(accountInfo)); 
} 

// Bridge class 
public AccountInfo GetAccountInfo() { return client.GetAccountInfo(); } 

// Client class 
public AccountInfo GetAccountInfo() 
{ 
    string respond = Command("AccountInfo"); 
    return new AccountInfo(respond); 
} 

private string Command(string command) 
{ 
    var pipe = new ClientPipe(pipeName); 
    pipe.Connect(); 
    return pipe.Command(command); 
} 

我想在命令處理期間解凍UI。還有其他可以執行的命令。最後所有的命令都在Client中的Command(string command)方法。

我試圖通過使用任務和ContinueWith打破管理器中的鏈,但它導致管道無法連接。原因是客戶端不是線程安全的。

// Manager class 
public void RequestAccountInfo() 
{ 
    var task = Task<AccountInfo>.Factory.StartNew(() => bridge.GetAccountInfo()); 
    task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); }); 
} 

我的問題是:在哪裏使用任務,ContinueWith和在哪裏鎖?

我想我只能鎖定Command(string command),因爲這是最終的方法。

private string Command(string command) 
{ 
    lock (pipeLock) 
    { 
     var pipe = new ClientPipe(pipeName); 
     pipe.Connect(); 
     return pipe.Command(command); 
    } 
} 

我可以在Client類中使用Task,Wait在Command中嗎?

+0

所以你的應用程序應該是異步的一路? – ilansch

+0

是的,我希望。有5-10個可以打開的視圖。他們每個人都有自己的Bridge和Client的副本。還有從每個視圖可以給出5-6個命令。所有這些都必須發送到其他線程的某處。但我不知道在命令鏈中的哪個位置。並且還在鎖鏈中。 –

+0

使用'Task'時會拋出什麼錯誤? – MoonKnight

回答

0

我在客戶端類鎖定Command。看來,它完全以這種方式,沒有阻塞UI,沒有管的錯誤。我鎖定pipeName因爲視角的每個副本使用唯一的管道名稱

我將Task<Type>,ContinueWith應用於Manager類中的所有命令。

// Manager class 
public void RequestSomeInfo() 
{ 
    var task = Task<SomeInfo>.Factory.StartNew(() => bridge.GetSomeInfo()); 
    task.ContinueWith(t => { OnInfoUpdated(new InfoEventArgs(t.Result)); }); 
} 

// Client class 
private string Command(string command) 
{ 
    lock (pipeName) 
    { 
     var pipe = new ClientPipe(pipeName); 
     pipe.Connect(); 
     return pipe.Command(command); 
    } 
} 
0

我認爲你遇到的問題是bridge.GetAccountInfo()試圖從UI本身提取信息 - 因此是UI線程。此代碼

public void RequestAccountInfo() 
{ 
    var task = Task<AccountInfo>.Factory.StartNew(() => bridge.GetAccountInfo()); 
    task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); }); 
} 

被試圖執行bridge.GetAccountInfo()方法(訪問UI)從後臺線程池線程。

我的第一個問題是撥打bridge.GetAccountInfo()的電話費用是多少?如果它不昂貴,那麼在這個方面進行多線程工作就沒有意義了。如果價格昂貴,你將不得不考慮一種方法來使這個操作線程安全(我不能建議沒有更多的信息)。

要做的另一件事就是評估遷移到WCF的費用。這爲您處理大多數同步問題......我很抱歉,我無法提供更多幫助。我在閱讀你最後的評論前寫了上面的內容。

我希望這有些用處。


另外:要注意的是SynchronizationContext。使用TaskScheduler,您可以在UI線程上啓動Task(這不是您想要的,因爲這又會阻止用戶界面 - 但是,這可以很好地知道何時報告[在.NET 4.0中]。上面的UI線程上,你可以做

public void RequestAccountInfo() 
{ 
    var task = Task<AccountInfo>.Factory.StartNew(() => 
     bridge.GetAccountInfo(), 
     TaskScheduler.FromCurrentSynchronizationContext()); 
    task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); }); 
} 
+0

「拋出對bridge.GetAccountInfo()的調用是多麼昂貴?」這不是最大1秒。我試圖這樣做,希望使用多任務將釋放UI以執行更重要的自動命令給Bridge。但現在開始意識到這是無稽之談。我必須鎖定某處,因爲管道一次只能執行一個命令。因此,由於管道的性質,負責執行此AccountInfo命令的事件可以(並且將)阻止其他命令。 –

+0

「移至WCF」。目前這是不行的。我對這項技術並不熟悉。該Bridge是從其他程序員僱用編寫的,它使用管道另一端的非託管C++ dll。我與其通信的其他應用程序無法導入.NET dll。 –