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

有没有办法让代理在特定的线程上运行?

说我有:

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

我是否可以拥有一致的后台长时间运行线程,并在需要时调用我自己的代理。 它必须每次都是相同的线程。

[编辑]

我希望它在专用线程上的原因是时间是我打算在它上面运行委托并在y毫秒后挂起线程,并在我运行另一个委托时恢复线程。 我觉得这是不可能的。 我将有一个委托队列,让线程的主要function从它读取并运行。

为了澄清一个具体的例子,我有一个带有一堆玩家线程的游戏系统。 我希望每个playerthread都可以在其上运行游戏事件的事件处理程序。 如果事件处理程序花费太多时间,我希望能够通过暂停其线程来暂停该特定玩家直到下一个事件。

因此,有一个专用线程,我可以运行多个事件处理程序,我可以暂停一个特定的玩家的AI,以防它被窃听或花费太长时间。

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

或者,您可以使用ActionThread中的ActionThread创建一个具有内置Action 代理队列的普通线程。

但是,这些都不会直接解决另一个需求:“暂停”一个动作并继续另一个动作的能力。 要做到这一点,您需要在每个操作中撒上“同步点”,并有办法保存其状态,重新排队并继续下一个操作。

所有这些复杂性几乎都接近线程调度系统,因此我建议退一步并进行更多的重新设计。 您可以允许每个操作排队到ThreadPool (我建议每个操作都是一个Task对象)。 你仍然需要使用“同步点”,但不是保存状态并重新排队,你只需要暂停(阻止)它们。

不幸的是,在任何通用线程上都没有内置任何function。 您可以通过创建一个包装Thread并实现ISynchonizeInvoke的类来实现此目的。

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

最后,正如警告一样,我建议您在专用线程上使用Semaphore或EventWaitHandle而不是Thread.Sleep。 它绝对比不必要时一遍又一遍地执行你的背景循环更友好。

通常,我建议只使用线程池或BackgroundWorker类 – 但这些并不保证在任何特定线程上都会发生工作。 目前还不清楚为什么你关心哪个线程运行工作,但假设它确实有点重要……

您必须通过某种共享内存(如队列)传递Delegate对象。 后台线程必须观察此队列,在它们存在时从其中拉出委托,然后执行它们。

如果事实certificate线程池可以运行代码,那么您总是可以使用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 ); 

对于您创建的线程,您只能在创建它们时指定ThreadStart委托。 没有规定将不同的委托注入到创建的线程中。 线程池的不同之处在于它允许您将代理提交给它代表您启动的先前创建的线程。

目前尚不清楚你要解决的问题是什么。 你想通过尝试在一个线程上运行多个委托来完成(或避免)什么?

这是我为在特定线程上运行某些东西而实现的模式。 这样做的好处是可以在阻塞工作调用之前或之后启动特定线程。 这是一个名为Watin的COM对象包装器,用于操作Internet Explorer的实例,该实例对上下文非常敏感。 它可以扩展为删除Thread.Sleep() ,可能使用AutoResetEvent ,这将在某些情况下大大提高性能。

这种模式的想法来自Justin Breitfeller,Stephen Cleary和LBushkin的答案。

  private Instantiate() { BrowserQueue = new ConcurrentQueue(); 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 BrowserQueue;