非赢表C#应用程序同步事件处理程序线程执行 [英] Synchronous Event Handler thread execution in non-Win Form C# app

查看:130
本文介绍了非赢表C#应用程序同步事件处理程序线程执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我运行了一些时间\\ CPU密集型进程(TimeExpensive型)此起彼伏。主线程(A)开始TimeExpensive过程在另一个线程(B)和异步变为无效。于完成时,线程B火灾主叫方的完成处理程序同步,并开始下一个TimeExpensive进程线程B.创建一个新的线程(C),但开始℃之后,B完成。因此,对数处理,n个线程的创建和大多数的时候,他们不并存。

不妨一其线性单线程的方式实现,但TimeExpensive由第三方执行,而它运行时,它使用的所有系统内核并运行了几个小时。

  //这将运行控制台应用程序
类节目
{
    静态无效的主要(字串[] args)
    {
        新计划()StartJobs()。
    }    无效StartJobs()
    {
        主要mainJob =新的Main();
        mainJob.MainCompletionEvent + =
                     新的动作<对象,EventArgs的>(mainJob_MainCompletionEvent);
        mainJob.Start();
    }    无效mainJob_MainCompletionEvent(对象发件人,EventArgs的发送)
    {
        //如果(成功)Environment.Exit(0);
    }}主类
{
    INT processCounter = 0;
    公共事件动作<对象,EventArgs的> MainCompletionEvent;
    公共无效启动()
    {
        这里//...do其他重要任务...
        processCounter ++;
        TimeExpensive TE =新TimeExpensive();
        te.CompletionEvent + =新动作(TimeExpensive_CompletionHandler);
        螺纹aThread =新主题(te.Run);
        aThread.IsBackground = FALSE;
        aThread.Name =TimeExpensive主题:+ processCounter;
        aThread.Start();
    }    无效TimeExpensive_CompletionHandler()
    {
        Console.WriteLine(当前线程名称:+ Thread.CurrentThread.Name);
        //启动另一个进程在后台,如果
        如果(processCounter小于5)
        {
            开始();
        }
        其他
        {
            Console.ReadKey();
            如果(JobCompletionEvent!= NULL)
                JobCompletionEvent(这一点,新的EventArgs());
        }
    }
}类TimeExpensive
{
    公共事件行动CompletionEvent;    公共无效的run()
    {
        //做一次昂贵的任务
        // ...        //当完成通知完成处理...
        如果(CompletionEvent!= NULL)
        {
            CompletionEvent();
        }
    }
}//输出
当前线程名称:TimeExpensive主题:1
当前线程名称:TimeExpensive主题:2
当前线程名称:TimeExpensive主题:3
当前线程名称:TimeExpensive主题:4
当前线程名称:TimeExpensive主题:5

上面的实现模仿我描述的行为。被窃听我的东西是事件处理程序同步运行,直到下一个线程启动,在此期间,它做很多,它不是专为任务。

不知道这是好的,是有办法,我可以回去线程在线程B的完成处理一下呢?或者我应该更好地使用其他delegate.BeginInvoke启动事件处理程序的执行?

我希望用简单而安全的方法做。任何帮助是极大的AP preciated。

P.S我看了很多帖子,但没有人用这种情况下处理好。

修改

静态主加入到展示如何来启动的控制台应用程序这个code。记得有一个还可以创建用户界面以启动主的工作。它一定会创造BackgroundWorker的线程创建mainJob对象并运行它。
谢谢!


解决方案

  

有没有一种方法我可以回去线程在线程B的完成处理一下呢?


没有,你没有到位的管道元帅从一个线程到另一个电话。那种管道是由一个GUI应用程序的主线程提供。出于必要,用户界面​​是pretty根本线程安全的。有迹象表明,支持这种编组UI线程数实现细节。这就像在一个典型的实施生产者/消费者线程模型的使用者。

这需要一个线程安全队列和在读取队列中的消费者的循环。你可能认识到这是在Windows GUI应用程序的消息队列。随着消息循环调用GetMessage函数读取通知,并对其采取行动。封送一个呼叫现在简单,您只需发布一条消息到消息队列中,UI线程读取并执行请求。发帖是Control.BeginInvoke的WinForms和Dispatcher.BeginInvoke WPF的实现。

您一定可以实现这种同步自己的机制。在.NET 4 BlockingCollection类很容易。但是的的记住,你必须从根本上改变线程A执行的方式。入住响应发布到队列中的请求是非常重要的。什么样的问题,像BackgroundWorker的一类试图解决。请记住,在GUI消息循环的存在是因为它的必要的,UI不是线程安全的。一个控制台应用程序不(典型值)具有相同的一种负担,控制台是线程安全的。

I'm running a number of time\CPU intensive processes (TimeExpensive type) one after another. The Main thread (A) starts TimeExpensive process in another thread (B) asynchronously and becomes inactive. On Completion, Thread B fires caller's completion handler synchronously and starts next TimeExpensive process in thread B. A new thread (C) is created but After starting C, B finishes. So for n processes, n threads are created and most of time, they don't co-exist.

One may wish its implementation in linear single threaded way, but TimeExpensive is implemented by third party and while it runs, it uses all system cores and runs for hours.

//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

Above implementation mimics the behavior I described. The thing that is bugging me is the Event Handler running synchronously until the next thread starts and during this time, it's doing lots of tasks that it's not designed for.

Not sure if this is good, Is there a way I can go back to thread A while in Thread B's completion handler? or Should I better start event handler execution using another delegate.BeginInvoke?

I wish doing it with simple yet safe approach. Any help is greatly appreciated.

P.S I read lots of posts but no one was dealing well with this scenario.

Edit

Static main is added to show how to kick start this code in console app. Remember one can also create UI to start "Main" job. It'll definitely create BackgroundWorker thread to create mainJob object and run it. Thanks!

解决方案

Is there a way I can go back to thread A while in Thread B's completion handler?

No, you don't have the plumbing in place to marshal a call from one thread to another. That kind of plumbing is provided by the main thread of a GUI app. Out of necessity, user interfaces are pretty fundamentally thread-unsafe. There are several implementation details of a UI thread that support such marshaling. It acts like a consumer in a typical implementation of a producer/consumer threading model.

Which requires a thread-safe queue and a loop in the consumer that reads the queue. You may recognize this as the message queue in a Windows GUI app. With the message loop that calls GetMessage to read notifications and act on them. Marshaling a call is now simple, you just post a message to the message queue, the UI thread reads it and executes the request. Posting is implemented by Control.BeginInvoke for Winforms and Dispatcher.BeginInvoke for WPF.

You certainly can implement this synchronization mechanism yourself. The .NET 4 BlockingCollection class makes it easy. But do keep in mind that you have to fundamentally alter the way thread A executes. Staying responsive to requests posted to the queue is important. The kind of problem that a class like BackgroundWorker tries to solve. Keep in mind that the GUI message loop exists because it is necessary, UI isn't thread-safe. A console app doesn't (typically) have the same kind of burden, the console is thread-safe.

这篇关于非赢表C#应用程序同步事件处理程序线程执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆