Page 1 of 1

Delete thread with blocking function

Posted: Fri Oct 18, 2019 12:54 pm
by Ksawery
I currently have a function to delete and clean up all my threads when the application is closed (i'm using 3 wxThreads). Unfortunately one of the threads uses a blocking function call for incoming TCP/IP communication. The function will not return until communication is established, so in the case of no incoming connections, the wxThread will never be destroyed (as the while(TestDestroy()) condition will never be met). The thread never enters its destructor, and I'm unable to terminate the application correctly.

Is there a way to deal with this case in wxWidgets, or should I find a way to terminate the blocking function (it's from an external library - libmodbus, modbus_tcp_pi_accept() function). I was considering using the Kill() function to terminate the thread, but apparently its not safe.

Edit: the Kill() function doesn't help either.

Regards,
Ksawery

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:01 pm
by doublemax
I was considering using the Kill() function to terminate the thread, but apparently its not safe.
Can you set the length of the timeout? If not, Kill() is the only option. The main problem with this is that it can leak memory. But if happens only at app termination, that shouldn't be a problem.
Edit: the Kill() function doesn't help either.
Why not?

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:13 pm
by Ksawery
I use the following code to terminate the thread:

Code: Select all

    //Delete TCP/IP thread
    {
        wxCriticalSectionLocker enter(mbThreadCS);
        if (mbThreadTCP)
        {
            if (mbThreadTCP->Kill() != wxTHREAD_NO_ERROR)
                wxLogError("Can't delete the thread!");
        }
    }

    while (1)
    {
        {
            wxCriticalSectionLocker enter(mbThreadCS);
            if (!mbThreadTCP) break;
        }
        wxThread::This()->Sleep(1);
    }
The application gets stuck in the while(1) loop, since the thread destructor is never called:

Code: Select all

cThreadTCP::~cThreadTCP()
{
    close(socket);
    free(tcpQuery);
    wxCriticalSectionLocker enter(mbGateway->mbThreadCS);
    mbGateway->mbThreadTCP = NULL;
}
Should I delete the pointer manually after using Kill()?

Regards,
Ksawery

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:25 pm
by doublemax
since the thread destructor is never called:
That's normal when you use Kill.
Should I delete the pointer manually after using Kill()?
Actually i'm not 100% sure about this. I wouldn't, but you can try what happens if you do.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:27 pm
by alys666
you could not dream about correct killing thread if there is infinitely blocking function.
(that's why properly designed libraries MUST use timeouts).
variants
1. look if in your lib exists a timeouted function(often libs implement timeouted and not timeouted variants of the same function)
2. let your thread live till application end. he will die together with your application.
3. check if there could be a trick to send something to interface or device, to simulate incoming data, to resume blocked thread.

in reality in your sitaution case 2 is the most correct and simple.
bw the way, why tcp listening is not timeouted there???

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:34 pm
by alys666
Ksawery wrote:
Fri Oct 18, 2019 1:13 pm
I use the following code to terminate the thread:

Code: Select all

    //Delete TCP/IP thread
    {
        wxCriticalSectionLocker enter(mbThreadCS);
        if (mbThreadTCP)
        {
            if (mbThreadTCP->Kill() != wxTHREAD_NO_ERROR)
                wxLogError("Can't delete the thread!");
        }
    }

    while (1)
    {
        {
            wxCriticalSectionLocker enter(mbThreadCS);
            if (!mbThreadTCP) break;
        }
        wxThread::This()->Sleep(1);
    }
The application gets stuck in the while(1) loop, since the thread destructor is never called:

Code: Select all

cThreadTCP::~cThreadTCP()
{
    close(socket);
    free(tcpQuery);
    wxCriticalSectionLocker enter(mbGateway->mbThreadCS);
    mbGateway->mbThreadTCP = NULL;
}
Should I delete the pointer manually after using Kill()?

Regards,
Ksawery
pointer just points to the thread you have killed. nobody will set it to null except of you.
you sit in second loop because of it.
you killed thread object inside heap, os and scheduler, but your pointer still is not null.
your logic is wrong. just kill it and forget.
ps...
as doublemax i also not sure will Kill delete the thread object or not. seems not. because thread can be allocated statically.
if thread is "detached", then Kill MAYBE deallocates object.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:41 pm
by Ksawery
I still get the following message, despite using Kill():

Code: Select all

15:41:27: Debug: 1 threads were not terminated by the application.
So I guess I can't do anything until the blocking function returns? Im undertand though, that the thread is terminated, and the heap resources are freed anyway, when the app closes?

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:46 pm
by doublemax
Is it possible that libmodbus created an internal thread that's still running? Check the total number of threads of your application in the task manager.

When i google for libmodbus, i see a function modbus_set_response_timeout. Can you use that in your case?
https://libmodbus.org/docs/v3.0.6/modbu ... meout.html

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:49 pm
by alys666
debugger must show all app threads and and their names.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:55 pm
by alys666
Ksawery wrote:
Fri Oct 18, 2019 1:41 pm
I still get the following message, despite using Kill():

Code: Select all

15:41:27: Debug: 1 threads were not terminated by the application.
So I guess I can't do anything until the blocking function returns? Im undertand though, that the thread is terminated, and the heap resources are freed anyway, when the app closes?
app closing returns everything to OS. app works in virtual memory space, when you exit app, all threads will be killed, and all memory used by app will be marked as free.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 1:57 pm
by Ksawery
Here are the threads running in the application:

Code: Select all

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffddc8) at ../cPomiarWiazki.cpp:3
3       wxIMPLEMENT_APP(cPomiarWiazki);
[New Thread 0x7fffeb904700 (LWP 3993)]
[New Thread 0x7fffeb103700 (LWP 3994)]
[New Thread 0x7fffea3f1700 (LWP 3996)]
[New Thread 0x7fffe9bf0700 (LWP 3997)]
[New Thread 0x7fffe93ef700 (LWP 4001)]
[New Thread 0x7fffe8a70700 (LWP 4002)]
[Thread 0x7fffe8a70700 (LWP 4002) exited]
There are more threads than I explicitly create, so I guess some must belong to libmodbus. I'm not sure how to terminate those.

Regards,
Ksawery

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 2:11 pm
by alys666
cough...cough... it's definitely not linux :)
there is nothing in thread list, but addresses only ...
1. if your lib has internal threads and has not explicit functions kinda
stop_lib, terminate... you must not try to stop something inside it.
there is no big problem if you closed app with still working thread(s), OS will kill app process with his local threads.
in my apps I finish my threads, but app has other threads and who finishes them - it's not my business.

ps.
in reality you will have
1. mainthread(where you started main of you app)
2. some additional internal threads of system libs and wxWIdgets.
under linux i have : 3 system threads+main+created by me.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 3:43 pm
by doublemax
Asking a 3rd time: Are you sure you can't set the timeout for the blocking function? That would solve everything.

Re: Delete thread with blocking function

Posted: Fri Oct 18, 2019 5:34 pm
by Ksawery
cough...cough... it's definitely not linux
What do you mean, this is under Linux Mint, Eclipse IDE :D
if your lib has internal threads and has not explicit functions kinda
stop_lib, terminate... you must not try to stop something inside it.
I don't think the library provides any way to interact with internal threads, although some people have suggested solutions:

https://github.com/stephane/libmodbus/issues/173
Asking a 3rd time: Are you sure you can't set the timeout for the blocking function? That would solve everything.
Unfortunately, I don't think there is a way to set the timeout.

I will try some of the suggested solutions on Monday. If these won't work, I will just allow the OS to terminate any threads when the App closes.

Many thanks,
Ksawery

Re: Delete thread with blocking function

Posted: Sat Oct 19, 2019 2:40 pm
by Ksawery
I managed to find (what I hope is) a good solution to the problem, by following these recommendations:

https://github.com/stephane/libmodbus/issues/452

I made the TCP/IP socket non-blocking, using the following function:

Code: Select all

fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) | O_NONBLOCK);
This effectively makes the modbus_tcp_pi_accept() function non-blocking as well. The only downside to this, is that I need to poll the function repeatedly for new connections, which will use more CPU resources. However, as I understand from your previous recommendations, adding wxThread::This()->Sleep(1) in an "infinite" thread partially alleviates using too much CPU?

There is another TCP/IP function which is blocking: modbus_receive(). This function blocks the thread when a connection is established, but no messages are being received. Fortunately, a timeout for this function was provided, due to many user requests:

https://github.com/stephane/libmodbus/issues/95

So now i'm successfully able to terminate the thread, using the recommended code:

Code: Select all

    //Delete TCP/IP thread
    {
        wxCriticalSectionLocker enter(mbThreadCS);
        if (mbThreadTCP)
        {
            if (mbThreadTCP->Delete() != wxTHREAD_NO_ERROR)
                wxLogError("Can't delete the thread!");
        }
    }

    while (1)
    {
        {
            wxCriticalSectionLocker enter(mbThreadCS);
            if (!mbThreadTCP) break;
        }
        wxThread::This()->Sleep(1);
    }
Many thanks,
Ksawery