带手动复位事件的c#线程
我有一个应用程序,可以将从目录中的文本文件读取的数据导入数据库。我有一个UI,允许用户单击导入按钮并开始导入数据,当用户再次单击该按钮时,我希望停止导入这些文件中的数据。我开始使用线程来实现这一点,以便在导入数据时不会冻结UI。但是我有一些问题。我开始使用thread.Abort()在用户停止导入后终止线程,但当用户再次单击导入时,一些重复数据会添加到数据库中,因为它开始读取我不想要的文本文件的顶部。我被告知要使用ManualResetEvents和Thread.Join()触发以完成导入,但我不知道该如何工作。现在,我的代码如下所示:带手动复位事件的c#线程,c#,multithreading,forms,C#,Multithreading,Forms,我有一个应用程序,可以将从目录中的文本文件读取的数据导入数据库。我有一个UI,允许用户单击导入按钮并开始导入数据,当用户再次单击该按钮时,我希望停止导入这些文件中的数据。我开始使用线程来实现这一点,以便在导入数据时不会冻结UI。但是我有一些问题。我开始使用thread.Abort()在用户停止导入后终止线程,但当用户再次单击导入时,一些重复数据会添加到数据库中,因为它开始读取我不想要的文本文件的顶部。我被告知要使用ManualResetEvents和Thread.Join()触发以完成导入,但我
public ManualResetEvent event1 = new ManualResetEvent(false);
public Thread workerThread;
public Form1
{
InitializeComponent();
}
private void importButton_Click(object sender, EventArgs e)
{
if(importButton.Text == "Begin Import")
{
importButton.Text = "Stop Import";
//runs a service that begins reading and importing data and writing to
//a "console" box.
Service service = new Service(consoleBox);
//run the new thread to begin importing data
workerThread = new Thread(service.importData);
workerThread.Start();
}
else
{
importButton.Text = "Begin Import";
event1.Set();
while(!event1.WaitOne(TimeSpan.FromSeconds(4)))
{ //imports data for 30 more text files
service.importData(30);
workerThread.Join();
}
}
}
基本上,我试图做的是保持踏板循环,检查是否有任何文件要读取,如果有,然后导入数据,否则睡眠4秒钟。我应该为此使用线程计时器吗?我有点不确定该怎么办。使用timer来运行导入过程,而不是线程,并定义一个变量来检查用户是否请求停止,而不是
thread.Abort()
在此代码中使用System.Timers.Timer
。并将AutoReset
property标记为false,以便仅在用户未请求停止时导入数据
private System.Timers.Timer _importTimer = new System.Timers.Timer();
private volatile bool _requestStopImport = false;
public Form1()
{
InitializeComponent();
_importTimer.Interval = 4000;//4 seconds
_importTimer.AutoReset = false;//not automatically raise elapse event each time interval elapsed, only if we don't want to stop.
_importTimer.Elapsed += OnImportTimerElapced;
}
private void importButton_Click(object sender, EventArgs e)
{
if (importButton.Text == "Begin Import")
{
importButton.Text = "Stop Import";
StartImport();
}
else
{
importButton.Text = "Begin Import";
StopImport();
}
}
private void OnImportTimerElapced(object sender, System.Timers.TimerEventArgs e)
{
//runs a service that begins reading and importing data and writing to
//a "console" box.
Service service = new Service(consoleBox);//or maybe this would be a class level variable
service.importData();
if (!_requestStopImport)
{
_importTimer.Start();
}
}
private void StartImport()
{
_requestStopImport = false;
_importTimer.Start();
}
private void StopImport()
{
_requestStopImport = true;
_importTimer.Stop();
}
正如您所注意到的,您不必在此处使用ManualResetEvent
。但是,如果您希望在代码完成时收到通知,或者因此可以使用AutoResetEvent
或引发事件以进行更详细的示例检查。无论如何,不要通过调用thread.Join
或ManualResetEvent.WaitOne
来阻止UI线程。这正是你想要阻止的;冻结用户界面。相反,您需要创建初始状态设置为true
的MRE。然后在importData
方法中,您需要定期调用WaitOne
,查看导入是否应继续(当事件发出信号时)或暂停(当事件未发出信号时)
下面是如何在importData
方法中调用WaitOne
的大致示意图。显然,您需要进行调整以使其适合您的具体实现
private void importData()
{
foreach (string filePath in GetFilesInSomeDirectory())
{
event1.WaitOne(); // Block when the MRE is unsignaled.
}
}
然后从导入按钮。单击事件处理程序,您可以调用event1.Reset
暂停导入操作,或event1.Set
继续导入操作
此外,您应该尽一切努力避免调用Thread.Abort
。它通常会导致更多的问题,除非采取特别的几乎不可能的措施来避免损坏AppDomain的状态