非Win Form C#app中的同步事件处理程序线程执行

Imr*_*jad 2 c# multithreading asynchronous event-handling

我一个接一个地运行了一些时间\ CPU密集型进程(TimeExpensive类型).主线程(A)异步启动另一个线程(B)中的TimeExpensive进程并变为非活动状态.在完成时,线程B同步触发调用者的完成处理程序并在线程B中启动下一个TimeExpensive过程.创建一个新线程(C)但在启动C之后,B完成.因此,对于n个进程,创建了n个线程,并且大部分时间它们不共存.

人们可能希望以线性单线程方式实现它,但TimeExpensive由第三方实现,并且在运行时,它使用所有系统核心并运行数小时.

//This will run as console app 
class Program
{
    static void Main(string[] args)
    {
        new Program().StartJobs();
    }

    void StartJobs()
    {
        Main mainJob = new Main();
        mainJob.MainCompletionEvent += 
                     new Action<object, EventArgs>(mainJob_MainCompletionEvent);
        mainJob.Start();
    }

    void mainJob_MainCompletionEvent(object sender, EventArgs e)
    {
        //if(success) Environment.Exit(0);
    }

}

class Main
{
    int processCounter = 0;
    public event Action<object, EventArgs> MainCompletionEvent;
    public void Start()
    {
        //...do other important tasks here...
        processCounter++;
        TimeExpensive te = new TimeExpensive();
        te.CompletionEvent += new Action(TimeExpensive_CompletionHandler);
        Thread aThread = new Thread(te.Run);
        aThread.IsBackground = false;
        aThread.Name = "TimeExpensive Thread: " + processCounter;
        aThread.Start();
    }

    void TimeExpensive_CompletionHandler()
    {
        Console.WriteLine("current Thread Name: " + Thread.CurrentThread.Name);
        //Start another Process In Background if
        if (processCounter < 5)
        {
            Start();
        }
        else
        {
            Console.ReadKey();
            if (JobCompletionEvent != null)
                JobCompletionEvent(this, new EventArgs());
        }
    }
}

class TimeExpensive
{
    public event Action CompletionEvent;

    public void Run()
    {
        //doing time expensive task
        //...

        //when finish Notify completion Handler...
        if (CompletionEvent != null)
        {
            CompletionEvent();
        }
    }
}

//Output
current Thread Name: TimeExpensive Thread: 1
current Thread Name: TimeExpensive Thread: 2
current Thread Name: TimeExpensive Thread: 3
current Thread Name: TimeExpensive Thread: 4
current Thread Name: TimeExpensive Thread: 5
Run Code Online (Sandbox Code Playgroud)

以上实现模仿我描述的行为.困扰我的事情是事件处理程序同步运行,直到下一个线程开始,在此期间,它正在执行许多不是为其设计的任务.

不确定这是不是很好,有没有办法在线程B的完成处理程序中回到线程A?或者我应该使用另一个delegate.BeginInvoke更好地启动事件处理程序执行?

我希望用简单而安全的方法来做到这一点.任何帮助是极大的赞赏.

PS我读了很多帖子,但没有人处理好这个场景.

编辑

添加静态main以显示如何在控制台应用程序中启动此代码.记住,还可以创建UI来启动"主要"工作.它肯定会创建BackgroundWorker线程来创建mainJob对象并运行它.谢谢!

Han*_*ant 7

有没有办法在线程B的完成处理程序中回到线程A?

不,你没有管道来组织从一个线程到另一个线程的呼叫.这种管道由GUI应用程序的主线程提供.出于必要,用户界面基本上是线程不安全的.有一些支持这种编组的UI线程的实现细节.它在生产者/消费者线程模型的典型实现中充当消费者.

这需要线程安全队列和消费者中读取队列的循环.您可能会将其识别为Windows GUI应用程序中的消息队列.使用消息循环调用GetMessage来读取通知并对其进行操作.现在编组调用很简单,只需将消息发布到消息队列,UI线程就会读取它并执行请求.发布由Winform的Control.BeginInvoke和WPF的Dispatcher.BeginInvoke实现.

您当然可以自己实现此同步机制..NET 4 BlockingCollection类使它变得简单.但记住,您必须从根本上改变线程A的执行方式.保持对发布到队列的请求的响应非常重要.像BackgroundWorker这样的类试图解决的问题.请记住,GUI消息循环存在是因为它是必要的,UI不是线程安全的.控制台应用程序(通常)没有相同的负担,控制台是线程安全的.