Yunus Yurtturk
Yunus Yurtturk

Reputation: 529

C++ Builder, TIdTCPServer's Multithread Handling

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

Answers (2)

Remy Lebeau
Remy Lebeau

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

Gregor Brandt
Gregor Brandt

Reputation: 7799

VCL GUI access is not thread safe. Use TTHread::Synchronize or TThread::Queue to access the main thread.

Upvotes: 0

Related Questions