Reputation: 529
I have a Server program which uses TIdTCPServer and a client side program. I run my client program e.g 3 times on a single computer. Each time a client is connected, I try to add sometyhing to a Memo. Here is the problem. Since 3 clients are running at the sametime and trying to connect to the server, when I run my server application. Both clients connect at the same time and since TIdTCPServer handle client connection on seperate threads, it causes deadlock(or something like that). I try to use a mutex
// Creation of mutex.Inside the constructor of TCPConnection class
ListViewMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL); // unnamed mutex
//Somewhere else in my code
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;
}
That is all. When I run my server and clients connect, my server application freezes. It even can't reach the line 'RelaseMutex(...)' 3 times (previously assumed 3 clients were connected) When I remove Adapter->AddToMemo() line, It can reach the ReleaseMutex(...) line 3 times (but of course that code does nothing)
Am I using mutex in wrong way, or what is the problem here?
Upvotes: 0
Views: 1678
Reputation: 596457
TIdTCPServer
is multithreaded. Its OnConnect
, OnDisconnect
, and OnExecute
events run in the context of a worker thread. It is not safe to access VCL UI controls from outside of the main UI thread. Using a mutex is not adequate protection. UI code MUST be run in the main thread.
Indy has TIdSync
and TIdNotify
classes to delegate code to the main thread, similar to the TThread::Synchronize()
and TThread::Queue()
methods. Try something like this:
#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
is a self-freeing object, it will destroy itself after DoNotify()
has exited. So do not delete
it manually.
Upvotes: 1
Reputation: 7799
VCL GUI access is not thread safe. Use TTHread::Synchronize or TThread::Queue to access the main thread.
Upvotes: 0