c#如何正确地停止一个线程并重新启动它
本文关键字:一个 线程 重新启动 正确地 | 更新日期: 2023-09-27 17:52:50
我有一个方法,它做一些工作,并在它完成后调用一个方法。在这个新调用的方法中,我停止了线程。
但是,如果我停止线程,下面的所有行将不会被读取。有什么合适的方法来停止线程并重新启动它吗?
下面是我的代码片段:public partial class Form1 : Form
{
string strProvider;
MySqlConnection sqlConn;
MySqlCommand command;
MySqlDataReader Reader;
Thread workerThread;
public Form1()
{
InitializeComponent();
initializedb();
workerThread = new Thread(shows);
workerThread.Start();
workerThread.IsBackground = true;
public void shows()
{
string k;
command.CommandText = "SELECT * FROM imageframe1";
sqlConn.Open();
Reader = command.ExecuteReader();
while (Reader.Read())
{
k = (string)(Reader.GetValue(1));
pictureBox1.Image = Image.FromFile(k);
Thread.Sleep(3000);
}
sqlConn.Close();
stopthread();
}
public void stopthread()
{
workerThread.Abort();
//*************everything after this line wont run********
MessageBox.Show("end");
//Thread.Sleep(3000);
//workerThread.Start();
}
我在这里做的是一个图片幻灯片。所以我想停止线程,然后重新启动它,检查db是否有新的图像,然后重新运行整个程序而不是在里面循环会占用很多内存资源。但问题是,当我停止它,我不能运行任何东西之后。
谁能给初学者一些启发吗?有例子会对我理解很有帮助
这不是暂停程序的方法。如果您希望用户能够暂时暂停从阅读器读取数据,那么更好的处理方法是设置一些标志,让while循环在每次迭代时检查。永远不应该通过调用Thread.Abort
直接操作线程。因此,你的"stopthread"方法应该看起来更像这样,而不是试图停止线程:
private object lockObject = new object();
private bool isPaused;
public void stopthread()
{
lock (lockObject)
{
isPaused = true;
}
//*************everything after this line wont run********
MessageBox.Show("end");
}
现在,为了真正尊重这个暂停动作,你必须修改读数来检查这个标志。一种方法是检查它是否在每次从读取器读取的迭代中暂停,如果是,等待直到它变为未暂停:
public void shows()
{
...
while (Reader.Read())
{
while (true)
{
lock (lockObject)
{
if (!isPaused)
break;
}
Thread.Sleep(1000);
}
k = (string)(Reader.GetValue(1));
pictureBox1.Image = Image.FromFile(k);
Thread.Sleep(3000);
}
...
}
当然,您还需要一个"startThread"方法:
public void startThread()
{
lock (lockObject)
{
isPaused = false;
}
MessageBox.Show("start");
}
这种方法的缺点是它使SQL连接保持打开状态,并且在暂停时绑定线程。另一种方法是记住处理了多少行,并在取消暂停时重新启动线程,从停止的地方开始。您可能希望以类似的方式停止线程——如果线程已暂停,检查标志并关闭连接,并在停止时进行清理。然后,当取消暂停时,您将不得不从一个新线程开始进程,以某种方式设法跳过您已经处理过的线程—可能涉及调整SQL。
最后要考虑的是使用线程池而不是手动创建线程,尽管对于WinForms应用程序来说,成本可能是无关紧要的。
这是一个关于c#线程的系列文章。真的,我是说真的。你可能想看看它,因为寻找解决方案时,处理线程不仅是找到一个解决方案,但最重要的是真正理解发生了什么除了;)
http://www.albahari.com/threading/我奶奶总是说"不要乱动线程"…她是对的……
我建议查看ManualResetEvent类。您可以让线程等待UI线程发出信号,然后继续。ManualResetEvent类可以有两种状态:有信号或无信号。线程可以调用WaitOne(),它在状态变为有信号状态之前不会返回(或者在状态已经有信号状态时立即返回)。通过调用set()将其设置为有信号,并通过调用reset()将其重置为无信号:
public partial class Form1 : Form
{
string strProvider;
MySqlConnection sqlConn;
MySqlCommand command;
MySqlDataReader Reader;
Thread workerThread;
ManualResetEvent manualReset;
public Form1()
{
InitializeComponent();
initializedb();
workerThread = new Thread(shows);
workerThread.Start();
workerThread.IsBackground = true;
manualReset = new ManualResetEvent(true); // true for allow running
}
public void shows()
{
string k;
command.CommandText = "SELECT * FROM imageframe1";
sqlConn.Open();
Reader = command.ExecuteReader();
while (Reader.Read())
{
k = (string)(Reader.GetValue(1));
pictureBox1.Image = Image.FromFile(k);
Thread.Sleep(3000);
manualReset.WaitOne(); // wait if reset
}
sqlConn.Close();
stopthread();
}
public void pauseThread()
{
manualReset.ReSet();
}
public void continueThread()
{
manualReset.Set();
}
}
然而,为什么不简单地在表单上放置一个计时器,并将间隔设置为3000毫秒,然后在UI线程中加载图像呢?看起来您只是从数据库中获取文件名。如果没有太多,你应该将它们预加载到一个列表中,并跟踪你的位置,而不是保持一个打开的连接和阅读器。1万个100个字符的字符串只占用大约200k的内存。