【问题标题】:C++ CLI Invoke issuesC++ CLI 调用问题
【发布时间】:2016-10-17 18:12:40
【问题描述】:

我有一个 MainForm 类(如您所料,它是一个表单),上面有一个文本框。我还有另一个名为“Application_Server”的类,它可以做很多其他的事情(不仅仅是与表单背景相关,还有很多基于网络的东西等)。

Application_Server 类在它自己的线程中运行,但需要能够更新表单上的控件,对于这个问题,我们将只使用文本框。

问题是,即使我正在执行命令以通过“调用”设置 textBox 控件的文本,但在运行时仍然出现以下异常:

附加信息:跨线程操作无效:控制 从线程以外的线程访问的“DebugTextBox” 创建于。

这可能是什么原因造成的?我肯定在 MainForm 中调用了一个委托。

以下是相关代码段(为便于阅读而删减):

MainForm.h:

public ref class MainForm : public System::Windows::Forms::Form {

        delegate void del_updateDebugText(String^ msg);
        del_updateDebugText^ updateDebugText = gcnew del_updateDebugText(this, &MainForm::postDebugMessage);

private: void postDebugMessage(String^ message);
};

MainForm.cpp:

void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
    Monitor::Enter(DebugTextBox);
    if (this->DebugTextBox->InvokeRequired)
    {
        this->Invoke(updateDebugText, gcnew array<Object^> { message });
    }
    else
    {
        this->DebugTextBox->AppendText(message);
    }
    Monitor::Exit(DebugTextBox);
}

最后,调用它的代码:

void ServerAppManager::postDebugMessage(System::String^ message)
{
    mainFormHandle->updateDebugText(message);
}

void ServerAppManager::applicationStep()
{
    postDebugMessage("Starting\n");
    // This is Run in seperate thread in MainForm.cpp
    while (s_appState == ApplicationState::RUN)
    {       
        postDebugMessage("Testing\n");      
    }

}

谢谢!

【问题讨论】:

  • 一切似乎都很好,但您使用MainForm 而不是TextBox 调用Invoke()。您可以尝试使用TextBox 致电Invoke(),看看是否有帮助。如果这样可以解决问题,则意味着 TextBox 可能是在与 MainForm 不同的线程上创建的,这似乎不正确。
  • 这段代码不会死锁吗?对Invoke() 的调用将导致在UI 线程上调用postDebugMessage(),这将导致它等待由调用线程持有的DebugTextBox...
  • 是的,它确实陷入了僵局,出于兴趣,你会如何巧妙地做到这一点,以免它不会?我下面的示例(将 Invoke 调用推送到另一个调用该方法的对象)看起来很乱,例如,如果我忘记调用怎么办?

标签: multithreading c++-cli command-line-interface invoke


【解决方案1】:

从名为 bwSearch 的后台工作人员中,我们从 DoWork 事件处理程序中执行以下调用:

private: System::Void bwSearch_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
    //... logic
    UpdateTxtOutput("Some message"); 
    //... more logic 
}

我有一个名为txtOutput的RitchTextBox,包含此代码的windows窗体控件也称为frmMain,UpdateTxtOutput定义如下:

       delegate void UpdateTxtOutputDelegate(String^ text);

       void UpdateTxtOutput(String^ text)
       {
           UpdateTxtOutputDelegate^ action = gcnew UpdateTxtOutputDelegate(this, &frmMain::Worker);
           this->BeginInvoke(action, text);
       }

       void Worker(String^ text)
       {
           txtOutput->AppendText("\t" + text + "\n");
       }

【讨论】:

    【解决方案2】:

    我设法通过将“MainForm”类中的方法简化为:

    void EagleEye_Server::MainForm::postDebugMessage(String^ message)
    {
        Monitor::Enter(DebugTextBox);
        DebugTextBox->AppendText(message);
        Monitor::Exit(DebugTextBox);
    }
    

    然后将“Invoke”调用移至调用委托的方法,虽然不是很漂亮,但现在可以使用。我认为这个问题可能是由于表单卡在 Invoke 循环中造成的。我这么说是因为我注意到表单在遇到递归 Invoke 语句后会锁定并停止响应。

    【讨论】:

    • 我没有将此标记为答案,因为我确信这是解决此问题的更好方法,并且如果有人发布解决方案,我愿意投票作为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    相关资源
    最近更新 更多