概述
昨天在写一个串口自动调试工具的时候,需要实现按下一个按钮开始自动调试,按下中止按钮,中止调试。
那么这就需要自动调试的过程是非阻塞式的。
以前遇到需要多任务运行的时候都是使用非阻塞式轮询,这次打算使用多线程进行,结果遇到了一系列问题,所幸最终解决了,并记录如下。
应用场景
任何需要多线程运行任务的情况,比如抽奖程序,按下开始,再次按下停止等等,且在各种游戏中运用广泛。
目标
1、使用一个按钮启动并关闭子线程,并对本线程的
开始
多线程
首先,写了一个按钮的方法,然后生成子线程,通过公屏
public partial class MainWindow : Form { // 单例 static public MainWindow mainWindow; private string currentTime; private bool isAutoCalibStart; // 自动校准子线程 private AutoCalibThread autoCalibThread; Thread childThread; public MainWindow() { InitializeComponent(); mainWindow = this; TheadInit(); } private void MainWindow_Load(object sender, EventArgs e) {} private void TheadInit() { autoCalibThread = new AutoCalibThread(); childThread = new Thread(new ThreadStart(autoCalibThread.StartautoCalib)); isAutoCalibStart = false; } private void AutoCalibStartButton_Click(object sender, EventArgs e) { if (isAutoCalibStart) { isAutoCalibStart = false; childThread.Abort(); } else { isAutoCalibStart = true; if (childThread != null) { childThread.Start(); } } } // 发送消息到消息框 public void SendToMsgBox(string msg, bool isNextLine = true) { if (isNextLine) { this.MsgBox.AppendText(msg + "\r\n"); } else { this.MsgBox.AppendText(msg); } } }
然后出现了第一个问题
好吧,仔细一想也是,这种窗口控件的访问本质上不是线程安全的。如果有两个或多个线程操作同一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的
于是,想到的第一个方法是,把
但是还是打算看看网上的方法,一个是启用线程间操作。
CheckForIllegalCrossThreadCalls = false;
另一个是使用委托。感觉第一个等于没解决,无异于看见
委托
参考网上
//以下内容由三个类中的代码块拼接而成 //声明委托,注意委托参数表需要与被委托参数表一致 class DelegateCollection { public delegate void MsgSendDategate(string msg, bool isNextLine = true); } //声明子线程,并在子线程类中定义委托以方便直接调用 class AutoCalibThread { public DelegateCollection.MsgSendDategate msgSendDategate; public void StartautoCalib() { for (int i = 1; i < 10; i++) { Thread.Sleep(1000); if (msgSendDategate != null) { msgSendDategate(i.ToString()); } } } } //重写任务函数(即被委托函数)[注意该函数在拥有被调用控件地类中] public void SendToMsgBox(string msg, bool isNextLine = true) { if (this.MsgBox.InvokeRequired) { BeginInvoke(autoCalibThread.msgSendDategate, new object[] { msg, isNextLine }); } else { if (isNextLine) { this.MsgBox.AppendText(msg + "\r\n"); } else { this.MsgBox.AppendText(msg); } } } //进行委托绑定[注意该函数在拥有被调用控件地类中] private void TheadInit() { autoCalibThread = new AutoCalibThread(); autoCalibThread.msgSendDategate = new DelegateCollection.MsgSendDategate(SendToMsgBox); childThread = new Thread(new ThreadStart(autoCalibThread.StartautoCalib)); }
小错误
使用委托成功地让子线程控制了其他线程地状态,但还是遇到了个小问题,在杀死线程后重新启动出现报错“线程正在运行或被终止;它无法重新启动
Hi Dear, are you in fact visiting this web site daily, if so then you will absolutely get good experience. Fayre Jefferey Adriene
Thank you! Actually, I had someone design it for me. Matilde Agustin Belsky
I cannot thank you enough for the article post. Really looking forward to read more. Keep writing. Karlotta Lucian Manchester