2014-01-24 102 views
0

我有一個使用TIdTCPServer和客戶端程序的服務器程序。 我在一臺計算機上運行我的客戶端程序,例如3次。每次客戶端連接時,我都會嘗試添加一些東西到備忘錄中。這是問題。由於3個客戶端在同一時間運行並嘗試連接到服務器,所以當我運行我的服務器應用程序時。兩個客戶端同時連接,並且由於TIdTCPServer在單獨的線程上處理客戶端連接,所以會導致死鎖(或類似情況)。我嘗試使用互斥C++ Builder,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; 
} 

這是所有。當我運行我的服務器和客戶端連接時,我的服務器應用程序凍結。它甚至不能達到'RelaseMutex(...)'行3次(以前假設有3個客戶端連接) 當我刪除Adapter-> AddToMemo()行時,它可以到達ReleaseMutex(...)行3次(但當然代碼什麼都不做)

我是以錯誤的方式使用互斥鎖,或者這裏有什麼問題?

回答

0

VCL GUI訪問不是線程安全的。使用TTHread :: Synchronize或TThread :: Queue來訪問主線程。

+0

嗨,感謝您的回覆。我無法訪問Synchronize或Queue方法,因爲TIdTCPServer的執行或onConnect方法(TIdTCPServer本身)不是從TThread類派生的。我認爲爲了使用Synchronize或Queue方法可以使用它們,如果它們用於派生自TThread的類中 –

+0

我正在使用從TObject派生的TCPServer類。現在我將TObject改爲TThread,並從中派生出我的TCPServer,我可以使用Synchronize()方法。但仍然不知道它是否能夠準確工作。謝謝 –

+1

我相信TThread :: Queue和TThread :: Synchronize的靜態版本不需要從TThread派生類。 –

1

TIdTCPServer是多線程的。它的OnConnect,OnDisconnectOnExecute事件在工作線程的上下文中運行。從主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