我有一个带有2个按钮和一个文本框的UI。
当用户按下“接收”按钮时,将启动一个线程以进行无限的工作循环(从多播接收和打印消息)。当用户按下“停止”按钮时,线程将获得“杀死标志”,然后程序将等待Join()
完成。
该无限工作循环使用SetTextBoxText(System::String)
方法返回UI文本框。这导致了竞争状况。有时,线程会很好地完成Join()
。其他人,该程序永远挂在Join()
上。
我相信这是因为,当UI线程在其工作线程上调用Join()
时,该工作线程可能处于其循环的中间,并正在尝试调用锁定的线程。 UI线程正在等待Join()
,并且无法执行任何操作(例如SetTextBoxText
)。
因此,在出现竞争状况或死锁时,我需要一种方法来检查control
是否可用。如果是这样,则调用该方法以正常方式打印。如果该方法不可用,请不要尝试调用SetTextBoxText
方法并像往常一样继续进行。
代码时间,我实际上是在使用UserControl
,而不是单独的文本框,button1和button2。我称UserControl
为“ MyUserControl”。它包含以下代码:
System::Void MyUserControl::buttonReceive_Click(System::Object^ sender, System::EventArgs^ e)
{
//each MyUserControl has their own myThread
this->myThread = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &MyUserControl::WorkLoop));
this->workLoopFlag = true;
this->myThread->Start();
}
void MyUserControl::WorkLoop()
{
while (this->workLoopFlag == true)
{
System::Threading::Thread::BeginCriticalRegion();
//this->myThread->BeginCriticalRegion();
Process();
//this->myThread->EndCriticalRegion();
System::Threading::Thread::EndCriticalRegion();
}
}
void EntityStatePduProcessor::Process()
{
//These 2 lines are for getting the correct MyUserControl to edit. Stored in GlobalVars::myList
ThreadPredicate^ threadPred = gcnew ThreadPredicate(System::Threading::Thread::CurrentThread->ManagedThreadId);
UserControlDataCollection^ userControlDataColl = GlobalVars::myList->Find(gcnew System::Predicate<UserControlDataCollection^>(threadPred, &ThreadPredicate::IsMatch));
System::Threading::Thread::BeginCriticalRegion();
if (userControlDataColl != nullptr) //should only happen after killing a thread
{
MyUserControl^ controlToEdit = (MyUserControl^)System::Windows::Forms::Control::FromHandle(userControlDataColl->control);
if (controlToEdit != nullptr)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
controlToEdit->SetTextBoxConsoleText("a system::string to place into the textbox");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
else
{
System::Windows::Forms::MessageBox::Show("controlToEdit == nullptr");
}
}
System::Threading::Thread::EndCriticalRegion();
}
delegate void MyStringDelegate(System::String ^ text);
void MyUserControl::SetTextBoxConsoleText(System::String^ input)
{
if (this->InvokeRequired) // (this->consoleTextBox->InvokeRequired)
{
MyStringDelegate^ myStrDel = gcnew MyStringDelegate(this, &MyUserControl::SetTextBoxConsoleText);
this->Invoke(myStrDel, gcnew array<Object^> { input });
}
else
{
this->textBoxConsole->Text = input;
this->textBoxConsole->Refresh();
}
}
System::Void MyUserControl::buttonStop_Click(System::Object^ sender, System::EventArgs^ e)
{
this->workLoopFlag = false; // kill the endless while loop
this->myThread->Join();
}
我试图按时间顺序发布代码,并仅在解释//comments
中的空白时包含要点。
导致挂起的代码在Process()
中用//~~~
概述的第三个方法中显示。
如何正确确保controlToEdit
仍然可以访问而不仅仅是等待Join()
?