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

时间:2010-08-13 22:26:08

标签: c# multithreading delegates

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

说我有:

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

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

[编辑]

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

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

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

5 个答案:

答案 0 :(得分:3)

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

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

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

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

答案 1 :(得分:2)

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

的类来实现此目的

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

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

答案 2 :(得分:1)

通常,我建议只使用线程池或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 :(得分:0)

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

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

答案 4 :(得分:0)

这是我实现的在特定线程上运行某些内容的模式。这样的好处是,可以在进行阻塞性工作调用之前或之后启动特定线程。这是为一个名为Watin的COM对象包装程序提供的,该包装程序用于处理Internet Explorer的实例,该实例对上下文非常敏感。可以对其进行扩展以删除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; ,这将在某些情况下大大提高性能。

这种模式的想法来自贾斯汀·布雷特菲勒(Justin Breitfeller),史蒂芬·克利(Stephen Cleary)和LBushkin的答案。

document.getElementById("formid").reset();        // Reset form values after form submission