如何同步BackgroundWorker与串口操作以避免竞争条件?
串口访问线程同步解决方案咨询
我通过BackgroundWorker实现每30秒更新Form控件:后台线程打开COM端口读取仪器数据,再通过ReportProgress()更新UI。同时Form上的ToggleSwitch也需要打开同一个COM端口修改仪器状态,为避免串口访问的竞争条件,必须在ToggleSwitch.StateChanged触发时暂停BackgroundWorker,保证同一时间只有一个线程访问串口。
以下是我的代码片段:
private void BackgroundWorkerStatus_DoWork(object sender, DoWorkEventArgs e) { try { while (!BackgroundWorkerStatus.CancellationPending) { // 获取新值(打开COM端口,读取状态) ReadState(); // 更新用户界面 BackgroundWorkerStatus.ReportProgress(0); // 等待下次更新 Thread.Sleep(UpdateInterval); } } catch { MessageBox.Show(….) } } private void BackgroundWorkerStatus_ProgressChanged(object sender, ProgressChangedEventArgs e) { try { // 更新Form上的控件 } catch { MessageBox.Show(….); } } private void ToggleSwitch_StateChanged(object sender, NationalInstruments.UI.ActionEventArgs e) { // 打开COM端口,设置状态,更新Form }
我已经尝试过两种方法但都无效:
- 在
StateChanged事件开头调用CancelAsync(),操作完成后调用RunWorkerAsync()重启后台线程,但因为后台线程运行到中途时才检测CancellationPending,无法及时终止当前的串口访问操作。 - 用全局布尔变量标记是否需要暂停,在
DoWork循环中判断,但同样存在检测不及时的问题。
我还试过用Semaphore做同步,但导致后台线程更新UI时出现跨线程异常,虽然知道原因但不知道怎么解决。
本质上我需要结合Semaphore和BackgroundWorker来同步这个可更新UI的后台任务,请问合适的实现方式是什么?
内容的提问来源于stack exchange,提问作者Dan Z
相关产品推荐
相关产品推荐

