多线程程序挂在控制方法调用上

时间:2018-08-09 17:08:11

标签: multithreading c++-cli deadlock race-condition

我有一个带有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()

0 个答案:

没有答案