2014-01-24 101 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