Winforms Windows窗体:后台工作程序同步和管理
我有一个问题,以下,非常简单的情况是我的项目的一部分。考虑下面的GUI如下: 我有两个背景工人:Winforms Windows窗体:后台工作程序同步和管理,winforms,visual-c++,asynchronous,c++-cli,backgroundworker,Winforms,Visual C++,Asynchronous,C++ Cli,Backgroundworker,我有一个问题,以下,非常简单的情况是我的项目的一部分。考虑下面的GUI如下: 我有两个背景工人: plot_bgworker-在本例中,它增加plot counter data_bgworker—在本例中,它增加数据计数器 我还有label_timer,它可以更新我表单上显示的递增值 为了管理后台工作人员和计时器,我编写了两个函数: private: void turnOnAcquisition() { if (!counting_paused) return;
- plot_bgworker-在本例中,它增加plot counter
- data_bgworker—在本例中,它增加数据计数器
private: void turnOnAcquisition() {
if (!counting_paused)
return;
if (!plot_bgworker->IsBusy)
plot_bgworker->RunWorkerAsync();
if (!data_bgworker->IsBusy)
data_bgworker->RunWorkerAsync();
label_timer->Enabled = true;
counting_paused = false;
}
private: void turnOffAcquisition() {
if (counting_paused)
return;
if (plot_bgworker->IsBusy)
plot_bgworker->CancelAsync();
if (data_bgworker->IsBusy)
data_bgworker->CancelAsync();
label_timer->Enabled = false;
counting_paused = true;
}
然后,单击每个按钮时会发生以下情况:
// Pauses counting on click
private: System::Void stop_btn_Click(System::Object^ sender, System::EventArgs^ e) {
turnOffAcquisition();
}
// Starts counting on click
private: System::Void start_btn_Click(System::Object^ sender, System::EventArgs^ e) {
turnOnAcquisition();
}
// Should restart counting on click, beginning from 0 (no matter what state counting is in right now)
private: System::Void restart_btn_Click(System::Object^ sender, System::EventArgs^ e) {
plot_counter = 0;
data_counter = 0;
turnOffAcquisition();
turnOnAcquisition();
}
最后,这里是我的后台工作程序(通过CancelAsync()/RunWorkerAsync()关闭/打开)和计时器:
// Calculating data counter
private: System::Void data_bgworker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
for (;;) {
data_counter++;
Sleep(50);
if (data_bgworker->CancellationPending) {
e->Cancel = true;
return;
}
}
}
// Calculating plot counter
private: System::Void plot_bgworker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
for (;;) {
plot_counter++;
Sleep(120);
if (plot_bgworker->CancellationPending) {
e->Cancel = true;
return;
}
}
}
// Display counters
private: System::Void label_timer_Tick(System::Object^ sender, System::EventArgs^ e) {
plot_counter_label->Text = numToMStr(plot_counter);
data_counter_label->Text = numToMStr(data_counter);
}
启动按钮和停止按钮都按预期工作,但现在我有一个重启按钮的问题。当我在计数过程中单击它时,它似乎重置值并停止后台工作人员,但永远不会重新启动它们(正如我在调用TurnEngurn时所预期的那样)。但是,当我在计数关闭时单击它时,我可以按预期打开计数
我的第一个想法是,当我试图检查我的工作人员是否忙时,取消标志还没有设置为另一个值,但在调用之间使用Sleep()无效。另一种猜测是由于竞争条件失败,所以我尝试使用MemoryBarrier(),但我不知道库,也不确定它是否能工作。此外,我尝试使用联锁类,但无法将其正确用于void函数
1。这种思维方式正确吗?2.如果是,为什么simple Sleep()不起作用?
3.在这种情况下,我将如何使用上述任何一种方法,以及哪种方法最匹配?好的,我自己找到了解决方案。这里的问题是关于竞赛条件的-一个事件试图停止计数(这意味着引发另一个事件),然后再次开始计数(这是有问题的,因为我的函数(我猜)已经与第一个事件混杂在一起,可能第二个事件甚至没有添加到事件检测队列中)。如果我的解释有误,我希望下面有人批评我;) 下面是两个修改后的函数,它们正确地解决了线程管理问题。关键是让其他事件完成它们的工作,直到我达到期望的状态 当我想关闭计数时,我让应用程序从队列中执行事件,直到两个线程都不忙(“while”循环): 类似地,当我想重新开始计数时,我让应用程序执行事件,直到我检查两个线程是否都忙(同样是“while”循环):
private: void turnOffAcquisition() {
if (counting_paused)
return;
if (plot_bgworker->IsBusy)
plot_bgworker->CancelAsync();
if (data_bgworker->IsBusy)
data_bgworker->CancelAsync();
while((plot_bgworker->IsBusy) || (data_bgworker->IsBusy)) // Continue to process events until both workers stop working
Application::DoEvents(); // Then, you can process another thread requests! :)
label_timer->Enabled = false;
counting_paused = true;
}
private: void turnOnAcquisition() {
if (!counting_paused)
return;
if (!plot_bgworker->IsBusy)
plot_bgworker->RunWorkerAsync();
if (!data_bgworker->IsBusy)
data_bgworker->RunWorkerAsync();
while((!plot_bgworker->IsBusy) || (!data_bgworker->IsBusy)) // Continue to process events until both workers start working
Application::DoEvents(); // Then, you can process another thread requests! :)
label_timer->Enabled = true;
counting_paused = false;
}