Thread and GUI

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.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Thread and GUI

Post by ONEEYEMAN »

Hi, ALL,
I have a GUI application and there I have a class that doesn't know anything about the GUI.
What I plan to do is to create a function that will run in a thread and fill out some vector with the data. On the GUI side this vector will be read and the data will be populated inside the wxGrid. No writing will be performed from the GUI to this vector.
So now here is my questions:

1. AFAIU I don't need any locking mechanism, because there is only 1 writer, right?
2. What is the best way of checking the vector for a presence of new element? Because I want to update the statusbar with the number of elements when they are added. Or maybe I should clear the vector inside the GUI?

Thank you
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Thread and GUI

Post by PB »

I think the only case where no thread synchronization is needed when there are only read accesses to std::vector and similar. Once you start writing there (e.g., adding or removing its elements), you need to sync.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

1. AFAIU I don't need any locking mechanism, because there is only 1 writer, right?
You still need to prevent that reading and writing happens at the same time.
2. What is the best way of checking the vector for a presence of new element? Because I want to update the statusbar with the number of elements when they are added. Or maybe I should clear the vector inside the GUI?
So the thread produces data which should then be appended to a wxGrid? And afterwards the data in the vector is not needed any more?

How many lines of data does the thread produce per second?

There are the usual three options to communicate from a worker thread to the main thread:
1) send an event
2) use a wxMessageQueue() (which you needed to poll in the main thread from a timer or idle event)
3) use Callafter inside the thread
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
What would people do here without you? ;-)
doublemax wrote: Sat Dec 26, 2020 10:58 pm
1. AFAIU I don't need any locking mechanism, because there is only 1 writer, right?
You still need to prevent that reading and writing happens at the same time.
OK, got it.
Resolution - don't have hopes too high! ;-)
doublemax wrote: Sat Dec 26, 2020 10:58 pm
2. What is the best way of checking the vector for a presence of new element? Because I want to update the statusbar with the number of elements when they are added. Or maybe I should clear the vector inside the GUI?
So the thread produces data which should then be appended to a wxGrid? And afterwards the data in the vector is not needed any more?
Correct.
doublemax wrote: Sat Dec 26, 2020 10:58 pm How many lines of data does the thread produce per second?
No idea.
But the execution is fast - basically DB querying.
doublemax wrote: Sat Dec 26, 2020 10:58 pm There are the usual three options to communicate from a worker thread to the main thread:
1) send an event
2) use a wxMessageQueue() (which you needed to poll in the main thread from a timer or idle event)
3) use Callafter inside the thread
Yes, I understand all that.
But as I said the thread function will not know anything about the GUI presence. There is no dependency.
So all 3 options are out.
But maybe I can somehow poll the vector inside the thread, grab the number of elements and send the event?
OTOH, in this case the thread won't have time to do its work as vector will be continuously locked from polling.
And I do want to update this with every single record retrieval.

So what is the best option here?

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

So the thread does not create a continuous stream of data, it's just the result of one SQL query?

Unless it takes more than 1-2 seconds, i wouldn't use a worker thread for that.

But if you have to use a thread, you need to establish some kind of communication between worker and gui. I would create a small interface class that's passed to the thread ctor. It would at the very least contain a callback that processes the data, and this would be called with CallAfter().

My second option would be wxMessageQueue, polled from a timer.
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
doublemax wrote: Sun Dec 27, 2020 12:19 am So the thread does not create a continuous stream of data, it's just the result of one SQL query?
Correct.
doublemax wrote: Sun Dec 27, 2020 12:19 am Unless it takes more than 1-2 seconds, i wouldn't use a worker thread for that.
Well the query may take some time to work.
Especially depending on the accessing library - ODBC will process it slower than the native one (extra layer), presence of indexes, network speed, etc.
doublemax wrote: Sun Dec 27, 2020 12:19 am But if you have to use a thread, you need to establish some kind of communication between worker and gui. I would create a small interface class that's passed to the thread ctor. It would at the very least contain a callback that processes the data, and this would be called with CallAfter().
I would prefer it as it seems easier to do.
Just create a thread where you execute a query and when you get all the data - thread dies.

Can you make some pseudo-code for me?
doublemax wrote: Sun Dec 27, 2020 12:19 am My second option would be wxMessageQueue, polled from a timer.
Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

As i had to test if my idea actually worked, i had to make a sample :)
Attachments
minimal.cpp
(9.26 KiB) Downloaded 83 times
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
I looked at the code and have one question.

As I said I want to set the counter (number of retrieved records on the statusbar after every record retrieval.

So basically it should be like this (for SQLite):

1. Prepare the query.
2. Start the loop
3. Execute sqlite3_step()
4. Update the status bar with the value of 1.
5. Process record 1.
6. Go to step 3.

Now - is it even doable like this?
Maybe I just need to check for the size of the vector somewhere?

Thank you.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
Sorry for the long delay.

After thinking more about this - what if I have a BLOB field with some images.

So, I think what I need to do is:

Code: Select all

1. Start a thread
2. Read a record
3. Send the record to GUI
4. Clean the vector
5. Read second record
Do you think its possible with small modification to that code?

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

You just need to redefine DBResultPayload, it can basically be anything.
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
I understand that.
However, is there a way for a thread to wait until the GUI finishes processing the record?

The 2 reasons I want a thread are:

1. DB communication does not depend on wxWidgets.
2. I should be able to cancel data retrieval.

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

For cancelling you can change the ProcessData() callback to return a value, one value could mean "cancel processing".
However, is there a way for a thread to wait until the GUI finishes processing the record?
For this i would add another method to DBResultConsumerInterface, e.g. bool ReadyToProcess() which the thread uses to check if the main thread is ready to process data. If it's not, just let the thread sleep a little bit.
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,

Will this work?

Code: Select all

wxThread::Entry()
{
    bool recordReceived = false;
    int success = db->PreareQuery();
    while( success )
    {
        success = db->GetRecord();
        if( success )
            recordReceived = true;
        ThreadEvent event();
        int rocessed = PostEvent( event );
        while( recordReceived && processed )
            sleep;
    }
}
Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Thread and GUI

Post by doublemax »

No. First of all i don't think it makes sense to send an event if you haven't received a record (recordReceived = false).

Code: Select all

        while( recordReceived && processed )
            sleep;
And neither recordReceived nor processed can change their value while this loop is running.
Use the source, Luke!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Thread and GUI

Post by ONEEYEMAN »

doublemax,
wxQueueEvent ques an event for later processing and therefore does not return any values.

So how do I check if the event is processed?

What do I modify in my pseudo-code?

Thank you.
Post Reply