Delete thread with blocking function Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Delete thread with blocking function

Post by Ksawery » Fri Oct 18, 2019 12:54 pm

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

User avatar
doublemax
Moderator
Moderator
Posts: 14793
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Delete thread with blocking function

Post by doublemax » Fri Oct 18, 2019 1:01 pm

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?
Use the source, Luke!

Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Re: Delete thread with blocking function

Post by Ksawery » 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

User avatar
doublemax
Moderator
Moderator
Posts: 14793
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Delete thread with blocking function

Post by doublemax » Fri Oct 18, 2019 1:25 pm

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.
Use the source, Luke!

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: Delete thread with blocking function

Post by alys666 » Fri Oct 18, 2019 1:27 pm

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???
ubuntu 16.04, wxWidgets 3.0.4

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: Delete thread with blocking function

Post by alys666 » Fri Oct 18, 2019 1:34 pm

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.
Last edited by alys666 on Fri Oct 18, 2019 1:47 pm, edited 1 time in total.
ubuntu 16.04, wxWidgets 3.0.4

Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Re: Delete thread with blocking function

Post by Ksawery » 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?
Last edited by Ksawery on Fri Oct 18, 2019 1:46 pm, edited 1 time in total.

User avatar
doublemax
Moderator
Moderator
Posts: 14793
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Delete thread with blocking function

Post by doublemax » Fri Oct 18, 2019 1:46 pm

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
Use the source, Luke!

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: Delete thread with blocking function

Post by alys666 » Fri Oct 18, 2019 1:49 pm

debugger must show all app threads and and their names.
ubuntu 16.04, wxWidgets 3.0.4

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: Delete thread with blocking function

Post by alys666 » Fri Oct 18, 2019 1:55 pm

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.
ubuntu 16.04, wxWidgets 3.0.4

Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Re: Delete thread with blocking function

Post by Ksawery » Fri Oct 18, 2019 1:57 pm

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

alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 317
Joined: Tue Oct 18, 2016 2:31 pm

Re: Delete thread with blocking function

Post by alys666 » Fri Oct 18, 2019 2:11 pm

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.
ubuntu 16.04, wxWidgets 3.0.4

User avatar
doublemax
Moderator
Moderator
Posts: 14793
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Delete thread with blocking function

Post by doublemax » Fri Oct 18, 2019 3:43 pm

Asking a 3rd time: Are you sure you can't set the timeout for the blocking function? That would solve everything.
Use the source, Luke!

Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Re: Delete thread with blocking function

Post by Ksawery » Fri Oct 18, 2019 5:34 pm

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

Ksawery
Experienced Solver
Experienced Solver
Posts: 74
Joined: Thu Jul 25, 2019 12:31 pm

Re: Delete thread with blocking function

Post by Ksawery » Sat Oct 19, 2019 2:40 pm

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

Post Reply