c# - 需要一种干净的方式在 C# 中的两个执行线程之间进行握手
问题描述
A 需要强制我的代码的某些功能在主线程上运行。我们正在与单线程黑匣子交谈,如果我从工作线程运行,我的性能是不可接受的。几个月来我一直在解决这个问题,方法是保存当前的同步上下文,然后使用 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 + ")");
}
}
解决方案
谢谢大家的建议。我最终发现了这个:
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)
将其重新插入我的完整程序也可以。
推荐阅读
- scala - 将函数列表传递给稍后使用提供的数据执行的方法
- python - 无法根据 w/np.where 条件在 pandas 中创建新的时间戳列
- r - r 中 read.csv.sql 的符号问题
- powershell - 数据网格视图。并行进入新行时运行作业
- c# - 重复作业中的下一次执行和最后一次执行是 N/A - hangfire
- .net - 没有突变的 F# 解决方案
- javascript - Sharepoint Office365 REST API 在浏览器中不起作用
- bluetooth-lowenergy - 如何使用 RxBluetooth 将多个订阅连接到 RxSwift 中的 Disposable?
- google-cloud-platform - 在 Google Cloud Platform 上实例化 VM(计算引擎)的脚本问题
- google-sheets - 最近几天的谷歌表格数据过滤器