簡體   English   中英

需要一種干凈的方式來在C#中兩個執行線程之間進行握手

[英]Need a clean way to handshake between two executing threads in C#

需要強制我的代碼的某些功能在主線程上運行。 我們正在談論一個單線程黑盒子,如果我從一個工作線程運行,我的表現是不可接受的。 通過保存當前的同步上下文然后使用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 + ")");
    }
}

您可以嘗試通過事件將委托傳遞給主線程:

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)
            {

            }
        });
    }
}

還要看一下這個問題本文關於控制台應用程序中同步上下文的實現。

謝謝大家的建議。 我最終發現了這個:

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)

將其重新插入我的完整程序也有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM