在提取所有数据之前打开窗体.如何让UI线程等待处理线程的第一个周期结束

本文关键字:线程 等待 UI 处理 结束 周期 第一个 数据 提取 窗体 开窗 | 更新日期: 2023-09-27 18:01:11

我的应用程序从实时提要中获取数据,对其进行处理并显示结果。此数据每5秒更新一次。在Main表单的Load事件中,我创建了一个线程来显示启动屏幕,该屏幕一直显示到第一个数据周期运行为止。

数据获取和处理线程(RecieveThread(调用RecieveFeed。我面临的问题是,在第一个循环完全运行之前,显示RecieveFeed中获取的数据的form2就会显示出来。如何确保只有在第一个周期完成数据提取后才加载form2。

主要形式的代码:

    private void frmMain_Load(object sender, EventArgs e)
    {
      Hide();
      // Create a new thread from which to start the splash screen form
      Thread splashThread = new Thread(new ThreadStart(StartSplash));
      splashThread.Start();
     //Thread to call the live feed engine. This thread will run for the duration of application
      ReceiverThread = new System.Threading.Thread(new System.Threading.ThreadStart(ReceiveFeed));
      ReceiverThread.Start();
      frmSecondForm form2 = new frmSecondForm();
      form2.MdiParent = this;
      form2.WindowState = FormWindowState.Maximized;
      Show();
      form2.Show();
    }   
    public frmRaceRace()
    {
        InitializeComponent();
        this.splash = new SplashScreen();
    }
    private void StartSplash()
    {
        splash.Show();
        while (!done)
        {
            Application.DoEvents();
        }
        splash.Close();
        this.splash.Dispose();
    }
    private void ReceiveFeed()
    {   
      while (!StopReceivingData)                    
      {
        foreach (...)
        {
         //Fetches data from live engine
         DLLImportClass.GetData1();
         //Manipulates and stores the data fetched in datatables                              
         ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { StoreData(); }))
         rowsProcessed++;
         if (!done)
         {
          this.splash.UpdateProgress(100 * rowsProcessed / totalRows);
         }
        } 
       done = true;        
       Thread.Sleep(5000);
     }
    }

在提取所有数据之前打开窗体.如何让UI线程等待处理线程的第一个周期结束

我认为这里需要使用的是System.Threading.AutoResetEvent。基本上,在你的表单类中添加一个成员:

private AutoResetEvent waitEvent_ = new AutoResetEvent(false); // create unininitialized

显示您的飞溅后,您需要等待此事件的信号:

private void StartSplash()
{
    splash.Show();
    // this will time out after 10 seconds.  Use WaitOne() to wait indefinitely.
    if(waitEvent_.WaitOne(10000))
    {
        // WaitOne() returns true if the event was signalled.
    }
} // eo StartSplash

最后,在您的处理函数中,当您完成时,只需调用:

waitEvent_.Set();

看起来您的代码中有一些竞争条件。

在使用WinForms和大多数(如果不是全部(UI框架进行线程处理时,只能从单个线程访问UI对象(窗体和控件(。

所有其他线程只能使用.InvokeRequired((和.BeginInvoke((访问该线程。这些调用可用于在UI线程中运行委托。参见:

{REDACTED:StackOverflow只允许我发布1个超链接。谷歌这些}

在BackgroundWorker类中有一个内置的快捷方式。

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

只需这样做(Psuedocode(:

public void StartSplash()
{
    Splash.Show();
    BackgroundWorker bgw = new BackgroundWorker();
    // set up bgw Delegates
    bgw.RunWorkerAsync();
}
public void bgw_DoWork( ... etc
{
    // do stuff in background thread
    // you cannot touch the UI from here
}
public void bgw_RunWorkerCompleted( ... etc
{
    Splash.close();
    // read data from background thread
    this.show();  // and other stuff
}

现在,您可以保证在数据传输之前不会关闭SplashScreen,也不会启动主窗口。

其他注意事项:您可能需要使用锁来保护您可能在后台线程中访问的数据。在不锁定的情况下,您永远不应该访问超过1个线程中的数据。

frmMain_Load更改为:

    private void frmMain_Load(object sender, EventArgs e)
    {
      Hide();
     //Thread to call the live feed engine. This thread will run for the duration of application
      ReceiverThread = new System.Threading.Thread(new System.Threading.ThreadStart(ReceiveFeed));
      ReceiverThread.Start();
      frmSecondForm form2 = new frmSecondForm();
      form2.MdiParent = this;
      form2.WindowState = FormWindowState.Maximized;
      StartSplash();
      Show();
      form2.Show();
    }