2015-09-04 132 views
0

在我的BackgroundWorker中,我需要使用非線程保存API定期構造和處理各種數據。我知道可以在主線程上調用一個Actions隊列,但我不知道如何從這個隊列返回一個值。c#定期從主線程返回值

那麼這怎麼可能呢?或者有沒有比BackgroundWorker更好的方法?

到目前爲止我只能找到this.Invoke,但是我不能使用它們,因爲API(Unity 5 Engine)不提供類似的功能。

我的環境只支持.NET 2.0。

編輯:我可能需要給予一定的exampels

假設Foo的constructur只能從mainthread叫,我需要做的這

TheInvokeMethode(() => { FooArray[i] = new Foo();}); 
SomeMethode(FooArray[i]); 

或assumming的BarAddComponent()能只能從MainThread調用

Bar SomeBar; 
TheInvokeMethode(() => { SomeBar.AddComponent()}); 

然而TheInvokeMethode只是表示包含的代碼應該在MainThread上執行。

+0

如果您使用的是Unity3D,則應將其添加到標籤中。我記得BackgroundWorker是Windows.Forms的一部分,它在Unity3D中不可用。 – Vlad

+0

@Vlad nope,BackgroundWorker在'ComponentModel'上,不知道Unity是否有它,但它沒有鏈接到'Windows.Forms',而是有一個方便的控件放入它。它應該在有'SynchronizationContext'(與Task.Run相同)的地方工作 – Jcl

+0

@Jcl Unity主線程沒有SynchronizationContext。你可以自己寫。 – Vlad

回答

0

BackgroundWorker的確有一個ReportProgress方法來觸發您可以訂閱的ProgressChanged事件。

一個過載接受一個「對象」作爲用戶 - 你可以用它來報告你的中間數據。

+0

是的,我知道,但我需要從MainThread返回數據。 – 00falc

0

讓對象存儲這些值有什麼問題?也許有些人表示這些值已經改變了?

通過適當的鎖定,這不應該是一個問題

更新

假設你已經可以調用在主線程你的行爲(如果沒有,可以this link提供一定的幫助,但我從來沒有使用統一所以你需要在統一論壇信任用戶),你可以使用這樣的模式:

某處:

object MyResult; 
bool MyResultIsModified = false; 

在代碼中的主線上:

// ... perform your actions here ... 

lock(MyResult) 
{ 
    MyResult = <data you want to gather on your thread>; 
    MyResultIsModified = true; 
} 

裏面你的線程/ BackgroundWorker的/不管循環:

lock(MyResult) 
{ 
    if(MyResultIsModified) 
    { 
    // ... do whatever with MyResult .. 
    MyResultIsModified = false; 
    } 
} 

如果MyResult是值類型,那麼你就需要有另一個目標爲宗旨鎖定,但這就是它

+0

看起來很有希望,我會檢查一下! – 00falc

1

在Unity中,您可以製作自己的調用,它將以與控件相同的方式工作。調用:

using System; 
    using System.Threading; 

    public class UnityInvoker : MonoBehaviour 
    { 
     public UnityInvoker Instance { get; private set; } 

     void Awake() 
     { 
      Instance = this; 
      _updateThread = Thread.CurrentThread; 
     } 

     Action _stored; 
     object _lock = new object(); 
     volatile Thread _updateThread; 

     public void Invoke(Action action) 
     { 
      if (_updateThread == Thread.CurrentThread) 
      { 
       lock (_lock) _stored += action; 
       Update(); 
       return; 
      } 
      using (var waiter = new ManualResetEvent(false)) 
      { 
       action +=() => waiter.Set(); 
       lock (_lock) 
        _stored += action; 
       waiter.WaitOne(); 
      } 
     } 

     void Update() 
     { 
      _updateThread = Thread.CurrentThread; 
      Action toDo; 
      lock (_lock) 
      { 
       toDo = _stored; 
       _stored = null; 
      } 
      if (toDo != null) 
       toDo(); 
     } 
    } 

將它放在任何遊戲對象上。

用法:

UnityInvoker.Instance.Invoke(()=>Application.Quit()); 

(如果需要)它可以被優化以互鎖。