【问题标题】:Event handling in multi thread c# winforms多线程 c# winforms 中的事件处理
【发布时间】:2023-03-14 01:01:01
【问题描述】:

我开发了在线程中完成事件处理的多线程应用程序。当 UI 线程中的事件引发时,会创建一个执行业务逻辑并终止的线程。但是,如果工作线程中的业务逻辑代码导致另一个事件; thread 调用主 UI 线程上的控制并继续其执行。同时,UI 线程为新的事件处理创建新线程。这两个线程都以并行方式执行。

我想要的是如果线程导致一个新事件;等待新的事件完成并继续他们的任务。事件应该按顺序处理。

我的任务实际上是大型框架的一部分。简而言之,应用程序通过使用反射 api 将控制事件绑定到目标代码。

当事件被捕获时,下面的 UI Thread 处理代码。

 Thread workerThread = new Thread(() => executeCommandTargetAsync( ..some parameters.. ));
 workerThread.Start();

工作线程通过使用 Control 的 InvokeRequired 标志和 Invoke 方法与 UI 线程进行通信。 在其他线程而不是 UI 线程中处理事件的目的是防止由于长时间的事件操作(例如从数据库更改组合框的数据源)而冻结 UI。

【问题讨论】:

  • 您能否给出一些简单的示例代码来演示您的问题?您的后台线程究竟是如何创建这些事件的?通过更改/与 UI 控件交互?
  • 如果你开始想等待动作完成并按顺序做事,你最好切换到调用方法(如果你不想要具体的依赖,在接口上)。跨度>

标签: c# multithreading winforms c#-4.0 event-handling


【解决方案1】:

尝试使用“AutoResetEvent”类:

 AutoResetEvent resetEvent = new AutoResetEvent(false);

 resetEvent.WaitOne();


 //pass the resetEvent object to thread 2, and when you want to continue processing the thread 1 you use the method resetEvent.Set();

【讨论】:

    【解决方案2】:

    在您的主 UI 线程中运行以下内容将是灾难性的,因为 UI 将被冻结且无响应。

    AutoResetEvent resetEvent = new AutoResetEvent(false);
    resetEvent.WaitOne();
    

    相反,您可以使用信号和计时器。 在您的 winforms 应用程序中创建一个事件参数队列或其他合适的包装器,以捕获引发事件的本质并将排队和出列包装在线程同步锁中

    在您创建而不是引发事件的单独线程中,将数据或信号排入队列。

    在您的 winodws 表单应用程序中有一个计时器,用于轮询队列中的任何新事件并相应地处理这些事件。

    如果您使用以下示例代码,则: 1) 当某个控件引发事件时,只需调用 EnqueueEvent 而不是启动新线程 2)在您的新线程中,您要做的就是使用新信号调用 EnqueueEvent 而不是引发事件。 当然,用更适合您的场景的东西替换 MyEventSignal 类,并将计时器代码放在实际的计时器处理程序中。

    public class MyEventSignal
    {
        public MyEventSignal()
        {
        }
        public MyEventSignal(object _Sender, EventArgs _Args)
        {
            Sender = _Sender;
            Args = _Args;
        }
        object Sender { get; set; }
    
        EventArgs Args { get; set; }
    }
    
    private static object syncRoot = new object();
    private static Queue<MyEventSignal> eventSignalQueue = new Queue<MyEventSignal>();
    public static void EnqueueEvent(MyEventSignal NewEventSignal)
    {
        lock (syncRoot)
        {
            eventSignalQueue.Enqueue(NewEventSignal);
        }
    }
    
    private static MyEventSignal DequeueEvent()
    {
        MyEventSignal result;
        result = null;
        lock (syncRoot)
        {
            if (eventSignalQueue.Count > 0)
            {
                result = eventSignalQueue.Dequeue();
            }
        }
        return result;
    }
    
    private void TimerUI_Tick(object sender, EventArgs e)
    {
        MyEventSignal newSignal;
        newSignal = DequeueEvent();
        while (newSignal != null)
        {
            // start new thread to do stuff based on event signal
            newSignal = DequeueEvent();
        }
    }
    
    
    private void DoStuffOnParalleThread()
    {
        System.Threading.ThreadStart MyThreadStart;
        System.Threading.Thread MyThread;
        MyThreadStart = new System.Threading.ThreadStart(WorkerThreadRoutine);
        MyThread = new System.Threading.Thread(MyThreadStart);
        MyThread.Start()
    }
    
    private void WorkerThreadRoutine()
    {
        // Do stuff
    
        //Instead of raising an event do this of course specify your event args
        // or change the MyEventSignal class to suit
        Form1.EnqueueEvent(new WinApp.Form1.MyEventSignal(this, EventArgs.Empty));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      相关资源
      最近更新 更多