有必要强制我的代码的某些功能在主线程上运行。我们正在谈论单线程黑匣子,如果我从工作线程运行,我的表现是不可接受的。我已经通过保存当前的同步上下文并使用Post调用一个将在主线程中执行的函数来解决这个问题。我知道这是针对GUI的,我不知道为什么它迄今为止一直有效,但是当我们使用必须与之兼容的旧版本的基础软件时,现在已经不一致了。
我已经写了这个基本示例来说明我的问题。我运行一个在新线程中运行的任务,并且在某个时候希望该线程能够要求主线程执行一些操作,然后希望工作线程能够继续执行。
这是当前输出:
Main (ThreadId = 1)
RunTask (ThreadId = 3)
CallBack (ThreadId = 4) << I want this to be ThreadId 1
如果该解决方案与当前解决方案非常接近,那么任何帮助都将是巨大的,甚至更好,因为我们距离发布版本还有几天的时间,我担心重大的重写可能导致更多的问题。谢谢!
public class Test
{
internal static SynchronizationContext _context;
internal static bool _busy = false;
static void Main(string[] args)
{
Console.WriteLine("Main (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
_context = SynchronizationContext.Current;
Task.Run(() => RunTask());
Console.Read();
}
public static Task RunTask()
{
Console.WriteLine("RunTask (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
_busy = true;
_context.Post(new SendOrPostCallback((o) =>
{
CallBack(null,
EventArgs.Empty);
}),
null);
while (_busy == true)
{
}
return null;
}
public static void CallBack(object sender, EventArgs e)
{
Console.WriteLine("CallBack (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
}
}
答案 0 :(得分:1)
您可以尝试通过事件将委托传递给主线程:
public class Test
{
public static BlockingCollection<Action> Handlers = new BlockingCollection<Action>();
static void Main(string[] args)
{
Console.WriteLine("Main (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
var task = new TaskWrapper();
task.CallBack += OnCallBack;
task.Run();
while (true)
{
var action = Handlers.Take();
action();
}
}
public static void OnCallBack(object sender, Action a)
{
Handlers.Add(a);
}
}
public class TaskWrapper
{
public event EventHandler<Action> CallBack;
public TaskWrapper()
{
CallBack += (sender, args) => { };
}
public void Run()
{
Task.Run(() =>
{
Console.WriteLine("RunTask (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
CallBack(this, () => Console.WriteLine("CallBack (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")"));
while (true)
{
}
});
}
}
还请参见this question和this article,了解如何在控制台应用程序中实现同步上下文。
答案 1 :(得分:1)
谢谢大家的建议。我终于找到了:
https://stackoverflow.com/a/20071498/10312402
和类似的解决方案解决了我的问题。现在是我的示例程序:
public static class DispatcherHelper
{
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
public class Test
{
internal static bool _busy = false;
internal static Dispatcher _dispatcher;
static void Main(string[] args)
{
Console.WriteLine("Main (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
_dispatcher = Dispatcher.CurrentDispatcher;
Task.Run(() => RunTask());
DispatcherHelper.DoEvents();
DispatcherHelper.DoEvents();
}
public static Task RunTask()
{
Console.WriteLine("RunTask (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
_busy = true;
_dispatcher.Invoke(new Action(CallBack));
while (_busy == true)
{
}
return null;
}
public static void CallBack()
{
Console.WriteLine("CallBack (ThreadId = " + Thread.CurrentThread.ManagedThreadId + ")");
_busy = false;
}
}
使用该代码,我得到了所需的输出:
Main (ThreadId = 1)
RunTask (ThreadId = 3)
CallBack (ThreadId = 1)
将其放回我的完整程序中也可以。