【问题标题】:C++ Builder, TIdTCPServer's Multithread HandlingC++ Builder,TIdTCPServer 多线程处理
【发布时间】:2014-01-24 09:36:04
【问题描述】:

我有一个使用 TIdTCPServer 的服务器程序和一个客户端程序。 我在一台计算机上运行我的客户端程序,例如 3 次。每次连接客户端时,我都会尝试在备忘录中添加一些东西。这是问题所在。由于 3 个客户端同时运行并尝试连接到服务器,因此当我运行我的服务器应用程序时。两个客户端同时连接,并且由于 TIdTCPServer 在单独的线程上处理客户端连接,它会导致死锁(或类似的东西)。我尝试使用互斥锁

// Creation of mutex.Inside the constructor of TCPConnection class
ListViewMutex = CreateMutex( 
    NULL,                       // default security attributes
    FALSE,                      // initially not owned
    NULL);                      // unnamed mutex

//我的代码中的其他地方

void __fastcall TCPConnection::OnConnect(TIdContext *AContext)
{
    DWORD dwWaitResult; 

    // Request ownership of mutex.

     dwWaitResult = WaitForSingleObject( 
        ListViewMutex,   // handle to mutex
        7000L);   // five-second time-out interval  
     Adapter->AddToMemo("OnConnect release");   
     ReleaseMutex(ListViewMutex);
     return; 
}

就是这样。当我运行我的服务器并且客户端连接时,我的服务器应用程序冻结。它甚至无法到达 'Re​​laseMutex(...)' 行 3 次(之前假设连接了 3 个客户端) 当我删除 Adapter->AddToMemo() 行时,它可以到达 ReleaseMutex(...) 行 3 次(但当然该代码什么都不做)

我是否以错误的方式使用互斥锁,或者这里有什么问题?

【问题讨论】:

    标签: c++ multithreading c++builder


    【解决方案1】:

    TIdTCPServer 是多线程的。它的OnConnectOnDisconnectOnExecute 事件在工作线程的上下文中运行。从主 UI 线程之外访问 VCL UI 控件是不安全的。使用互斥锁不足以提供保护。 UI 代码必须在主线程中运行。

    Indy 有 TIdSyncTIdNotify 类将代码委托给主线程,类似于 TThread::Synchronize()TThread::Queue() 方法。试试这样的:

    #include <IdSync.hpp>
    
    class AddToMemoNotify : class TIdNotify
    {
    protected:
        TMyAdapterClass *m_Adapter;   
        String m_Msg;
    
        virtual void __fastcall DoNotify()
        {
            m_Adapter->AddToMemo(m_Msg);   
        }
    
    public:
        __fastcall AddToMemoNotify(TMyAdapterClass *Adapter, const String &Msg) :
            TIdNotify(), m_Adapter(Adapter), m_Msg(Msg)
        {
        }
    };
    

    void __fastcall TCPConnection::OnConnect(TIdContext *AContext)
    {
        (new AddToMemoNotify(Adapter, "Client Connected")->Notify();
    }
    
    void __fastcall TCPConnection::OnDisconnect(TIdContext *AContext)
    {
        (new AddToMemoNotify(Adapter, "Client Disconnected")->Notify();
    }
    

    TIdNotify 是一个自我释放的对象,它会在DoNotify() 退出后自行销毁。所以不要手动delete它。

    【讨论】:

      【解决方案2】:

      VCL GUI 访问不是线程安全的。使用 TTHread::Synchronize 或 TThread::Queue 访问主线程。

      【讨论】:

      • 您好,感谢您的回复。我无法访问 Synchronize 或 Queue 方法,因为 TIdTCPServer(TIdTCPServer 本身)的执行或 onConnect 方法不是从 TThread 类派生的。我认为如果在从 TThread 派生的类中使用 Synchronize 或 Queue 方法,则可以使用它们
      • 我使用的是从 TObject 派生的 TCPServer 类。现在我将 TObject 更改为 TThread 并从中派生出我的 TCPServer,我可以使用 Synchronize() 方法。但仍然不知道它是否会正常工作。谢谢
      • 我相信有静态版本的 TThread::Queue 和 TThread::Synchronize 不需要你的类从 TThread 派生。
      • Indy 有自己的 TIdSyncTIdNotify 类,它们是 TThread::Synchronize()TThread::Queue() 的包装器。
      猜你喜欢
      • 2014-11-22
      • 2014-05-02
      • 2019-09-04
      • 2017-04-14
      • 2021-04-09
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多