如何强制等待在Console应用程序中的同一调用者线程中继续

时间:2018-06-01 09:44:42

标签: .net async-await task-parallel-library threadpool

我正在用C#编写.Net控制台应用程序。

我需要将基于事件的线程调用转换为异步方法。

例如:

public class WorkerClass
    {
        public EventHandler Progress;
        public EventHandler Finished;
        public void DoSomething()
        {
            Thread td = new Thread(Start);
            td.Name = "Worker Thread";
            td.Start();
        }

        private void Start()
        {
            int i = 0;
            while (i < 10)
            {
                Thread.Sleep(1000);
                i++;
                var progress = i * 10;
                Progress?.Invoke((object)progress, null);
            }
            Finished?.Invoke(null, null);
        }
    }



    Class MyMainClass
            {
                private static WorkerClass myWorkerClass;
                static void Main(string[] args)
                {
                    myWorkerClass = new WorkerClass();
                    RunAsynchronously(null);
                }
                private async void RunAsynchronously(EventHandler progress)        
                {           
                    //Main Thread Call

                    await DoSomethingAsync(progress);

                    //Resume after worker finished is not in main thread? :(
                    //Needed main thread to continue
                }
                private Task<int> DoSomethingAsync(EventHandler progress)
                {
                    var completionSource = new TaskCompletionSource<int>();

                    EventHandler Progress = null;
                    EventHandler Finished = null;

                    Finished = (o, e) =>
                    {
                        myWorkerClass.Finished -= Finished;
                        myWorkerClass.Progress -= Progress;
                        completionSource.SetResult(100);
                    };

                    Progress = (o, e) => { progress?.Invoke(o, e); };

                    myWorkerClass.Finished += Finished;
                    myWorkerClass.Progress += Progress;

                    myWorkerClass.DoSomething();            

                    return completionSource.Task;
                }
            }

由于某些限制,我需要主线程继续, 但是,在await恢复RunAsynchronously方法之后,当前线程与主线程(或调用await的线程)不同。

我知道如果调用者是UI线程,这种行为将自动生效,但在我的情况下,它是控制台应用程序,我没有UI。

请建议解决方案。 提前谢谢。

1 个答案:

答案 0 :(得分:0)

我觉得你对控制台应用程序和.NET应用程序的线程模型有什么期望有一个根本的误解。

控制台应用程序一直运行,直到其入口线程完成Main方法的执行。这意味着您要么让线程忙于工作,要么阻止线程直到另一个信号解除阻塞并允许该方法退出。它是一个非常简单的结构,旨在让您启动应用程序,完成一些工作,然后在您完成后退出。这意味着线程永远不会自由&#34;做其他工作;您无法在不完全将工作调度模型更改为更复杂的模型的情况下安排任务继续执行该线程。

在基于UI的应用程序中,您的应用程序遵循更复杂的模型。而不是应用程序执行某些工作,然后退出,而是主要线程被要求抽取消息队列,根据收到的消息进行工作,并且仅在收到&#34;退出&#34;信息。该模型采用单个线程并为其提供工作队列,每条工作都由消息发出信号。这使您可以在UI线程上获得Task简历。

这种混淆是为什么async void模式通常被认为是反模式的原因,当然为什么它只能在具有UI的应用程序中使用。由于非常具体的任务调度模型,应用程序只能正常工作。任何其他模型都会导致此构造中断,吞噬异常并使得无法知道工作何时完成。