【问题标题】:c++ multithreaded windows GUI (accessing the forms)c++多线程windows GUI(访问表单)
【发布时间】:2012-01-04 23:55:33
【问题描述】:

我编写了一个简单的控制台应用程序,使用 Windows 套接字作为服务器和客户端之间的代理。我决定制作一个图形界面来实时查看所有输入/输出数据包(就像一个非常简单的wireshark)。

服务器和客户端之间的连接运行在与消息循环不同的线程上。当服务器/客户端发送数据包时,我希望立即显示(例如添加到简单的文本控件)。

但由于除了消息循环所在的线程之外,我无法从其他线程访问表单,因此我不知道如何处理。

我在以下方面找到了几种解决方案: - 托管 C++ - C++/CLI - C#, 但如果不使用 .NET 平台,则并非如此。 (我对这个 GUI 主题真的很陌生,所以我什至不确定你是否可以在没有 .NET 的情况下使用 Windows 窗体)

也许 QT + C++ 可以解决这个问题,但除此之外还有其他解决方案吗?如果没有,是否可以在 C#/Java 中为原生 C++ 代码编写包装器?

肯定有很多用 C/C++ 编写的应用程序使用 GUI,一般的方法是什么?

【问题讨论】:

  • 从辅助线程向对话框发布自定义消息。

标签: c++ multithreading winapi user-interface wrapper


【解决方案1】:

您不能在不同的线程中访问窗口是绝对正确的。处理此问题的正确方法是使用 ::PostMessage Win32 API 命令(或者,如果您使用围绕 Win32 的包装器库,则该包装器中最终调用 PostMessage 的任何函数)发布消息。这是 Microsoft 关于消息队列的有用链接: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644928(v=vs.85).aspx

【讨论】:

    【解决方案2】:

    还有一个替代方案,免费且开源,称为 Nana C++ 库 (http://stdex.sourceforge.net),它是一个纯 C++ GUI 库。 通过使用 Nana 库,可以轻松解决多线程问题。 GUI 中的多线程上有an article,它会是您爱好项目的选择。

    【讨论】:

      【解决方案3】:

      快速而肮脏的 Win32 解决方案将涉及 UI 线程中的临界区、文本缓冲区和计时器。

      定义一些全局变量...

      CRITICAL_SECTION bufferLock; // critical section (to be initialized somewhere)
      char dataBuffer[65536]; // contains the data that will be sent to the form
      int newdata = 0; // how much data we got (this variable must be atomic, int is ok)
      char uiDataBuffer[65536]; // data available to the form
      int overflow = 0; // just in case...
      

      UI 线程计时器

      void onTimer ()
      {
           if (overflow)
           {
                // handle this
           }
           else
           if (newdata) // new data to display
           {
                // take the lock, copy the data and release the lock quickly
                EnterCriticalSection(&bufferLock);
                int dataread = newdata;
                memcpy(uiDataBuffer, dataBuffer, dataread);
                newdata = 0;
                LeaveCriticalSection(&bufferLock);
      
                // TODO: append the text in uiDataBuffer[] to your text control
           }
      }
      

      从工作线程调用:

      void sendData (char* data, int size)
      {
          EnterCriticalSection (&bufferLock);
          if(size+newdata > 65536)
              overflow = 1;
          else
          {
              memcpy(dataBuffer+newdata, data, size);
              newdata += size;
          }
          LeaveCriticalSection (&bufferLock);
      }
      

      代码未经测试。缓冲区大小和定时器频率有待调整。

      通过使用 PostMessage()(带有自定义消息)向 UI 发出新数据可用的信号,可以避免使用计时器轮询缓冲区。

      如果性能是一个问题,生产者和消费者线程之间的数据交换也可以通过无锁 FIFO 队列非常有效地执行。

      PostMessage() 单独不是解决方案在线程之间交换数据。

      【讨论】:

      • 两个答案都非常有帮助,谢谢他们。有没有优雅的方式来使用自定义消息? (我的意思是,如果我使用自定义消息 - 让它成为 PACKET_ARRIVED - 它必须具有 int 类型。如何确保它的值不与其他常量冲突?我是否应该简单地使用“足够大”的数字避免冲突?
      • 使用 RegisterWindowMessage() 获取唯一的“自定义”消息。
      猜你喜欢
      • 1970-01-01
      • 2015-03-17
      • 1970-01-01
      • 2015-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多