在提取所有数据之前打开窗体.如何让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);
}
}
我认为这里需要使用的是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();
}