Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Breaking out of TIdTCPClient::Connect() or Read() when quitting an app.



Permlink Replies: 2 - Last Post: Sep 4, 2017 8:27 PM Last Post By: Colin Maharaj
Colin Maharaj

Posts: 122
Registered: 12/2/99
Breaking out of TIdTCPClient::Connect() or Read() when quitting an app.
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 1, 2017 7:36 AM
So I have the Connect() and Read() functions
in a thread, and when I quit my app, I will do
the usual .....
delete IdTCPClient;
but the functions I mentioned may still be in call.

I did this recently and works ok-isk...

bool IdTCPClient_IN_Connect;
bool QuittingApp=false;
....
...

/// in the thread---------------------------------
IdTCPClient_IN_Connect=true;
IdTCPClient->Connect();
// and I also placed this below is a catch
IdTCPClient_IN_Connect=false;
if (QuittingApp==false)
{
// We never reach here if we are not connected.
IdTCPClient->IOHandler->RecvBufferSize = 65536;
}
//-----------------------------------------------

// in the exit function--------------------------
QuittingApp=true;
while (IdTCPClient_IN_Connect==true) Sleep(100);
delete IdTCPClient;
//-----------------------------------------------

My question is......
Is there a better way to break out of a Connect() or Read()
if they occur are in a thread.
I am using Indy10 on BCBXE4.

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Breaking out of TIdTCPClient::Connect() or Read() when quitting an app.
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 1, 2017 10:47 AM   in response to: Colin Maharaj in response to: Colin Maharaj
Colin Maharaj wrote:

So I have the Connect() and Read() functions
in a thread, and when I quit my app, I will do
the usual .....
delete IdTCPClient;

Don't do that until after the thread has been fully terminated first.

bool IdTCPClient_IN_Connect;

You shouldn't need that flag. Just use the fact that your thread is
still running.

bool QuittingApp=false;

Why are you using that flag instead of using the thread's own
Terminated property?

/// in the thread---------------------------------
IdTCPClient_IN_Connect=true;
IdTCPClient->Connect();
// and I also placed this below is a catch
IdTCPClient_IN_Connect=false;
if (QuittingApp==false)
{
// We never reach here if we are not connected.
IdTCPClient->IOHandler->RecvBufferSize = 65536;
}

// in the exit function--------------------------
QuittingApp=true;
while (IdTCPClient_IN_Connect==true) Sleep(100);
delete IdTCPClient;

This is the completely wrong approach.

You can't cause Connect() to exit prematurely (well, you can try using
Disconnect() in another thread context, but that is not guaranteed to
work). But you can assign a ConnectTimeout for it, and then exit the
thread after Connect() exits.

Same with reading. You can set a ReadTimeout. And various reading
methods also have their own timeout parameters.

During app shutdown, make sure to wait for your thread to terminate
before destroying the TCP client. It is not enough to wait for the
thread to not be inside of Connect(). You have to wait for it to stop
accessing the TCP client altogether.

Try something more like this instead:

class TMyThread : public TThread
{
...
protected:
    void __fastcall Execute();
    void __fatcall TerminatedSet(); // called by Terminate()
...
};
 
void __fastcall TMyThread::Execute()
{
    ...
 
    IdTCPClient->ConnectTimeout = ...;
 
    while (!Terminated)
    {
        try
        {
            IdTCPClient->Connect();
        }
        catch (const Exception &)
        {
            // handle the error as needed...
 
            if (!Terminated)
                Sleep(1000);
 
            continue;
        }
 
        try
        {
            try
            {
                if (Terminated)
                    return;
 
                // reading code here ...
                // check Terminated periodically...
            }
            __finally
            {
                IdTCPClient->Disconnect();
            }
        }
        catch (const Exception &)
        {
            // handle the error as needed...
 
            if (!Terminated)
                Sleep(1000);
        }
    }
}
 
void __fastcall TMyThread::TerminatedSet()
{
    try {
        IdTCPClient->Disconnect();
    }
    catch (const Exception &) {}
}


if (MyThread)
{
    MyThread->Terminate();
    MyThread->WaitFor();
    delete MyThread;
    MyThread = NULL;
}
delete IdTCPClient;


--
Remy Lebeau (TeamB)
Colin Maharaj

Posts: 122
Registered: 12/2/99
Re: Breaking out of TIdTCPClient::Connect() or Read() when quitting an app.
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 4, 2017 8:27 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks for the insight....

On 9/1/2017 1:47 PM, Remy Lebeau (TeamB) wrote:
Colin Maharaj wrote:

So I have the Connect() and Read() functions
in a thread, and when I quit my app, I will do
the usual .....
delete IdTCPClient;

Don't do that until after the thread has been fully terminated first.

bool IdTCPClient_IN_Connect;

You shouldn't need that flag. Just use the fact that your thread is
still running.

bool QuittingApp=false;

Why are you using that flag instead of using the thread's own
Terminated property?

/// in the thread---------------------------------
IdTCPClient_IN_Connect=true;
IdTCPClient->Connect();
// and I also placed this below is a catch
IdTCPClient_IN_Connect=false;
if (QuittingApp==false)
{
// We never reach here if we are not connected.
IdTCPClient->IOHandler->RecvBufferSize = 65536;
}

// in the exit function--------------------------
QuittingApp=true;
while (IdTCPClient_IN_Connect==true) Sleep(100);
delete IdTCPClient;

This is the completely wrong approach.

You can't cause Connect() to exit prematurely (well, you can try using
Disconnect() in another thread context, but that is not guaranteed to
work). But you can assign a ConnectTimeout for it, and then exit the
thread after Connect() exits.

Same with reading. You can set a ReadTimeout. And various reading
methods also have their own timeout parameters.

During app shutdown, make sure to wait for your thread to terminate
before destroying the TCP client. It is not enough to wait for the
thread to not be inside of Connect(). You have to wait for it to stop
accessing the TCP client altogether.

Try something more like this instead:

class TMyThread : public TThread
{
...
protected:
     void __fastcall Execute();
     void __fatcall TerminatedSet(); // called by Terminate()
...
};
 
void __fastcall TMyThread::Execute()
{
     ...
 
     IdTCPClient->ConnectTimeout = ...;
 
     while (!Terminated)
     {
         try
         {
             IdTCPClient->Connect();
         }
         catch (const Exception &)
         {
             // handle the error as needed...
 
             if (!Terminated)
                 Sleep(1000);
 
             continue;
         }
 
         try
         {
             try
             {
                 if (Terminated)
                     return;
 
                 // reading code here ...
                 // check Terminated periodically...
             }
             __finally
             {
                 IdTCPClient->Disconnect();
             }
         }
         catch (const Exception &)
         {
             // handle the error as needed...
 
             if (!Terminated)
                 Sleep(1000);
         }
     }
}
 
void __fastcall TMyThread::TerminatedSet()
{
     try {
         IdTCPClient->Disconnect();
     }
     catch (const Exception &) {}
}


if (MyThread)
{
     MyThread->Terminate();
     MyThread->WaitFor();
     delete MyThread;
     MyThread = NULL;
}
delete IdTCPClient;

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02