M.M
M.M

Reputation: 141618

Indy TCP client in thread

Following on from this thread, I am trying to make a C++Builder XE5 application with:

I have been unable to find any examples; the examples linked from the Indy Demos page all do not use any threads in their clients, so far as I can see.

My questions are:

Currently I take actions on the main form in response to every event, and also in response to receiving data on the socket. At the moment my code is full of temporary variables and stub functions because Synchronize requires a void(void) closure and it is quite spaghetti. So I wonder if I am taking a fundamentally wrong approach.

Upvotes: 1

Views: 1692

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596497

Should the TIdTCPClient be on the main form (as a design time component), or should it be a member variable of the thread class?

Either will work fine. What is important is that you call Connect() and other I/O methods in the context of the worker thread (inside its Execute() method).

In the events fired by the TIdTCPClient , does the code in the event handlers (which are member functions of my main form) need to be Synchronized?

Yes, if they are accessing UI controls, or other shared data that must be protected.

Is it safe for both the main VCL thread and the client thread to make function calls on the TIdTCPClient object?

That depends on the particular calls (for instance, sending outbound data from the main thread while reading inbound data in the worker thread, at least while the client is connected), but I would not suggest you rely on that. You should just keep all of your client-related actions in the worker thread only.

At the moment my code is full of temporary variables and stub functions because Synchronize requires a void(void) closure and it is quite spaghetti.

You can use Indy's TIdSync/TIdNotify classes to help you keep that spaghetti code better organized. For instance, derive a class from TIdSync, move your variables into it, and override its virtual DoSynchronize() method to call your Form method(s) as needed. Then you can create an instance of thee class, populate its variables if needed, call its Synchronize() method, read its variables if needed, and then free it.

#include <IdSync.hpp>

class TMySync : public TIdSync
{
protected:
    virtual void __fastcall DoSynchronize();
public:
    // variables...
};

void __fastcall TMySync::DoSynchronize()
{
    // call Form methods, use variables as needed...
}

void __fastcall TMyThread::Execute()
{
    //...
    TMySync *sync = new TMySync;
    // set variables as needed...
    sync->Synchronize();
    // read variables as needed...
    delete sync;
    //...
}

Upvotes: 1

Related Questions