2011-01-13 120 views
25

我正在創建一個自動化的測試運行應用程序。在這部分應用程序中,我正在使用一個輪詢服務器。它的工作原理是不斷輪詢Web服務器以確定何時應該運行新的自動化測試(對於我們的GUI應用程序的夜間自動運行)。如何將背景工作線程設置爲單線程公寓?

當輪詢服務器看到一個請求時,它下載所有需要的信息,然後在後臺工作者中執行測試運行。問題是測試運行的一部分有後臺工作線程中發生的OLE,COM和其他調用(例如,Clipboard.Clear())。當發生這些調用之一時,會發生以下異常:

在進行OLE調用之前,當前線程必須設置爲單線程單元(STA)模式。確保您的Main函數具有標記的STAThreadAttribute。

如何將後臺工作線程標記爲單線程公寓?我的Program.cs中的Main調用顯然已經具有該屬性。

+0

`Clipboard.Clear()`是不是COM它是原生的Windows API – Aliostad 2011-01-13 21:08:29

+7

剪貼板使用COM進行談判。剪貼板數據和格式 – 2011-01-13 21:11:50

回答

35

這是不可能的,BGW使用線程池線程。 TP線程始終是MTA,不能更改。您必須使用常規線程,並在啓動之前調用SetApartmentState()。這個線程也應該抽取一個消息循環,調用Application.Run()。

也許你應該考慮從UI線程調用這段代碼。因爲很可能,COM服務器無論如何都在UI線程上運行它的方法。將工作線程調用到創建COM服務器的STA線程是自動的,COM負責處理它。

或者把牛逼的角和自己的元帥。您可以創建您自己的STA線程,爲服務器提供一個快樂的家。您將在this post中找到代碼,請務必在Initialize()覆蓋中創建COM對象。

+1

+1 - 使用UI線程 – 2011-01-13 21:13:55

+0

我想這很有道理,因爲我真的看不到用於與應用程序交互的用法, test正在運行 – KallDrexx 2011-01-13 21:22:30

1

您通常通過在入口點定義attributre [STAThread()]來設置它(例如Static Main)。

+1

這隻適用於Main方法,不適用於後臺任務 – 2013-02-14 19:34:16

8

BackgroundWorker默認使用ThreadPool線程,但可以覆蓋此行爲。首先,你需要定義一個自定義SynchronizationContext

public class MySynchronizationContext : SynchronizationContext 
{ 
    public override void Post(SendOrPostCallback d, object state) 
    { 
     Thread t = new Thread(d.Invoke); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(state); 
    } 
} 

,並覆蓋默認的SynchronizationContext,這樣,你用你的BackgroundWorker之前:

AsyncOperationManager.SynchronizationContext = new MySynchronizationContext(); 

注:這可能對其餘性能的影響應用程序,因此您可能希望限制新的Post實現(例如,使用狀態參數)。

+0

對我無效DoWork方法仍然從MTA線程中調用 – Maxence 2015-07-10 14:41:24

3

我還沒有測試過它,但是如果你調用WinForms Form,你應該回到UI線程,大部分的東西都應該重新工作。

BackgroundWorker bgw = new BackgroundWorker(); 
bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork); 
bgw.RunWorkerAsync(); 

private void bgw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Invoke the UI thread 
    // "this" is referring to the Form1, or what ever your form is 
    this.Invoke((MethodInvoker)delegate 
    { 
     Clipboard.GetText(); 
     // etc etc 
    }); 
} 
-1

我用+康拉德德溼的想法和它的工作很棒!

雖然該代碼有一個小問題,但您必須關閉「this.Invoke .....「就像一個});

這裏是康拉德德溼的代碼與此修復程序:

BackgroundWorker bgw = new BackgroundWorker(); 
    bgw.DoWork += new DoWorkEventHandler(this.bgw_DoWork); 
    bgw.RunWorkerAsync();> 

    private void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // Invoke the UI thread 
     // "this" is referring to the Form1, or what ever your form is 
     this.Invoke((MethodInvoker)delegate 
     { 
      Clipboard.GetText(); 
      // etc etc 
     }); 
    } 
相關問題