c#定期从主线程返回值

时间:2015-09-04 10:17:49

标签: c# .net multithreading unity3d

在我的BackgroundWorker中,我需要使用非线程保存API定期构造和处理各种数据。我知道可以在主线程上使用Actions队列调用,但我不知道如何从这个队列中返回一个值。

那怎么可能呢?或者是否有比BackgroundWorker更好的方法?

到目前为止我只找到了this.Invoke的问题,但我无法使用它们,因为API(Unity 5引擎)不能提供类似的功能。

顺便说一下,我的环境只支持.NET 2.0。

编辑:我可能需要提供一些示例

假设只能从mainthread调用Foo的构造函数,我需要这样做

TheInvokeMethode(() => { FooArray[i] = new Foo();});
SomeMethode(FooArray[i]);
只能从MainThread调用

或假设AddComponent() Bar

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

然而,TheInvokeMethode只是表达包含代码应该在MainThread上执行的东西。

3 个答案:

答案 0 :(得分:1)

在Unity中,您可以创建自己的Invoke,其工作方式与Control.Invoke相同:

    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());

可以使用Interlocked进行优化(如果需要)。

答案 1 :(得分:0)

BackgroundWorker确实有一个ReportProgress方法可以触发您可以订阅的ProgressChanged事件。

一个重载接受"对象"作为用户 - 您可以使用它来报告您的中间数据。

答案 2 :(得分:0)

有一个对象存储这些值的问题是什么?也许还有其他一些表明这些价值观发生了变化?

通过适当的锁定,这不应该是一个问题

更新

假设您已经可以在主线程中调用您的操作(如果没有,sql_auto_is_null可能会提供一些帮助,虽然我从未使用过Unity,因此您需要信任用户统一论坛),您可以使用如下模式:

某处:

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

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

在主线程的代码中:

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

在你的线程/ backgroundworker /无论循环中:

MyResult

如果NSArrayController是值类型,那么您需要为锁定目的设置另一个对象,但是关于它