代码之家  ›  专栏  ›  技术社区  ›  Raynos

在特定的线程C上调用委托#

  •  9
  • Raynos  · 技术社区  · 14 年前

    有没有办法让委托在特定线程上运行?

    假设我有:

    CustomDelegate del = someObject.someFunction;
    Thread dedicatedThread = ThreadList[x];
    

    我可以有一个一致的后台长时间运行的线程,并在需要时调用自己的委托。每次都必须是同一个线程。

    [编辑]

    我希望它位于专用线程上的原因是时间,因为我打算在它上运行委托并在之后挂起线程 y 毫秒,并在运行另一个委托时恢复线程。我看这是不可能的。我将有一个委托队列,并让线程的主函数从中读取和运行。

    因此,有一个专用线程,我可以运行多个事件处理程序,我可以暂停一个特定的球员的人工智能,以防它被窃听或是花太长时间。

    5 回复  |  直到 14 年前
        1
  •  3
  •   Stephen Cleary    14 年前

    我认为最好的解决办法是 Task 对象并将它们排队到 StaThreadScheduler 运行单个线程。

    ActionThread 在里面 Nito.Async 创建具有内置队列的普通线程 Action 代表们。

    然而,这两种方法都不能直接满足另一种需求:即“暂停”一个动作并继续执行另一个动作的能力。要做到这一点,您需要在每个操作中撒上“同步点”,并有办法保存其状态,重新排队,然后继续执行下一个操作。

    ThreadPool 任务 对象)。您仍然需要散布“同步点”,但是您不需要保存状态并重新排队,只需要暂停(阻止)它们。

        2
  •  2
  •   LBushkin    14 年前

    通常,我建议只使用线程池或 BackgroundWorker 类-但这些不能保证工作将在任何特定线程上发生。现在还不清楚你为什么关心哪个线程运行这个工作,但是假设它确实有什么关系。。。

    Delegate 对象通过某种共享内存,比如队列。后台线程必须监视这个队列,当代理存在时将其从队列中拉出,然后执行它们。

    BeginInvoke

    // wrap your custom delegate in an action for simplicity ...
    Action someCode = () => yourCustomDelegate( p1, p2, p3, ... );
    // asynchronously execute the currying Action delegate on the threadpool...
    someCode.BeginInvoke( someCode.EndInvoke, action );
    
        3
  •  2
  •   Justin Breitfeller    14 年前

    ISynchonizeInvoke.

    一种简单的方法是在专用线程上创建一个事件处理队列,正如LBushkin提到的那样。我建议使用 Queue<Action> 类并直接调用动作委托。您可以使用匿名委托操作完成大多数需要的任务。

    最后,作为警告,我建议您使用信号量或EventWaitHandle,而不是Thread.Sleep 在你的专用线程上。它肯定比在不必要的情况下一遍又一遍地执行后台循环更友好。

        4
  •  0
  •   Ed Power    14 年前

    对于创建的线程,只能在创建它们时指定ThreadStart委托。没有将不同的委托注入已创建线程的规定。线程池的不同之处在于,它允许您将委托提交给以前创建的线程,该线程以您的名义启动。

        5
  •  0
  •   fartwhif    4 年前

    Thread.Sleep() ,可能有一个 AutoResetEvent

        private Instantiate()
        {
            BrowserQueue = new ConcurrentQueue<BrowserAction>();
            BrowserThread = new Thread(new ThreadStart(BrowserThreadLoop));
            BrowserThread.SetApartmentState(ApartmentState.STA);
            BrowserThread.Name = "BrowserThread";
            BrowserThread.Start();
        }
        private static void BrowserThreadLoop()
        {
            while (true)
            {
                Thread.Sleep(500);
                BrowserAction act = null;
                while (Instance.BrowserQueue.TryDequeue(out act))
                {
                    try
                    {
                        act.Action();
                    }
                    catch (Exception ex) { }
                    finally
                    {
                        act.CompletionToken.Set();
                    }
                }
            }
        }
        public static void RunBrowserAction(Action act)
        {
            BrowserAction ba = new BrowserAction() { Action = act, CompletionToken = new ManualResetEvent(false) };
            Instance.BrowserQueue.Enqueue(ba);
            ba.CompletionToken.WaitOne();
        }
        public class BrowserAction
        {
            public Action Action { get; set; } = null;
            public ManualResetEvent CompletionToken { get; set; } = null;
        }
        ConcurrentQueue<BrowserAction> BrowserQueue;