【发布时间】:2013-11-11 22:22:36
【问题描述】:
我正在编写一个消耗资源的库,无论出于何种原因,API 的设计方式都是在不同的线程上引发事件,但 API 的调用必须在主线程上完成。
假设我尝试使用的 API 定义为(我将省略事件定义):
public sealed class DodgyService
{
public void MethodThatHasToBeCalledOnTheMainThread() { ... }
}
为了使用这个 API,我在我的库中添加了一个名为 Service(是的,非常原始的名称)的服务,它将创建一个新任务(当我指定一个从SynchronizationContext)。
这是我的实现:
public class Service
{
private readonly TaskFactory _taskFactory;
private readonly TaskScheduler _mainThreadScheduler;
public Service(TaskFactory taskFactory, TaskScheduler mainThreadScheduler)
{
_taskFactory = taskFactory;
_mainThreadScheduler = mainThreadScheduler;
}
// Assume this method can be called from any thread.
// In this sample is called by the main thread but most of the time
// the caller will be running on a background thread.
public Task ExecuteAsync(string taskName)
{
return _taskFactory.StartNew(
() => ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(taskName),
new CancellationToken(false), TaskCreationOptions.None, _mainThreadScheduler)
.ContinueWith(task => Trace.TraceInformation("ExecuteAsync has completed on \"{0}\"...", taskName));
}
private void ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(string taskName)
{
Trace.TraceInformation("Starting \"{0}\" really long call...", taskName);
new DodgyService().MethodThatHasToBeCalledOnTheMainThread();
Trace.TraceInformation("Finished \"{0}\" really long call...", taskName);
}
}
现在,如果我(在主线程上)执行我的服务调用并尝试在主线程上等待,应用程序将进入死锁,因为主线程将等待已安排在主线程上执行的任务主线程。
如何在不阻塞整个进程的情况下将这些调用编组到主线程?
在某些时候,我想在创建新任务之前执行主线程的检测,但我不想破解这个。
对于任何感兴趣的人,我得到了一个要点 here,其中包含代码和一个显示该问题的 WPF 应用程序。
顺便说一句,该库必须在 .net framework 4.0 上编写
编辑! 我按照Scott Chamberlain 提供的here 提供的建议解决了我的问题
【问题讨论】:
-
您在任务列表中“等待”而不是“等待”在您的示例代码中的要点中,两者之间存在 非常 的重要区别两个。
-
你说得对,斯科特……这是一个错字。我已经更正了。
-
API 必须在 main 线程上还是 API 可以在第二个 STA 消息泵线程上运行? (使用示例见this answer)
-
我包装的 API 迫使我在主线程上调用它(不管我的应用程序/服务/什么会消耗它。
-
我的问题是什么构成了“主线程” 大多数需要在“主”线程上运行的东西实际上是在说它们需要在“一个 STA Windows 消息表明该对象最初是在“线程上创建的。我在问是否在您的应用程序中启动第二个消息泵(如链接的答案)对您有用。
标签: c# .net multithreading task-parallel-library