2015-09-04 92 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()); 

(如果需要)它可以被优化以互锁。