Events & secondary threads

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
wxJack
Experienced Solver
Experienced Solver
Posts: 83
Joined: Wed Jun 20, 2018 8:06 am

Events & secondary threads

Post by wxJack »

Hey there!
I have a doubt about the way wxWidgets handles the handling of events.

Scenario: I'm inside a secondary thread, and I want to send an event in order for the main one to process it and "do something".



I do something like :

Code: Select all

m_parent->GetEventHandler()->ProcessEvent(eventToBeProcessed);
I use Process Event, whose description is the following:
// Process an event right now: this can only be called from the main
// thread, use QueueEvent() for scheduling the events for
// processing from other threads.
Because I want the event to be processed immediately.

I know that I could have used the following line too

Code: Select all

m_parent->GetEventHandler()->AddPendingEvent(eventToBeProcessed);
I knew that in both of these cases, is the main thread to handle these events,
but I see from the call stack of visual studio that in the first case (ProcessEvent), a worker thread handles the event.
In the second case, the main thread does it. Why this behaviour?

thank you very much in advance!
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Events & secondary threads

Post by doublemax »

It's exactly as you said:
I use Process Event, whose description is the following:
// Process an event right now: this can only be called from the main
// thread, use QueueEvent() for scheduling the events for
// processing from other threads.
By calling ProcessEvent, the respective event handler will be called immediately in the same thread context as the caller.

QueueEvent or AddPendingEvent puts the event in the event queue and it will be handled as soon as possible from the main event queue in the main thread.
Use the source, Luke!
wxJack
Experienced Solver
Experienced Solver
Posts: 83
Joined: Wed Jun 20, 2018 8:06 am

Re: Events & secondary threads

Post by wxJack »

thank you very much for your answer
the respective event handler will be called immediately in the same thread context as the caller.
So, in order to avoid any misunderstanding, the event handler is immediately called by the worker/secondary thread (= the one you named the caller) but the event is processed by the main thread, right?
Just to make an example, the scenario is the following

Code: Select all

EVT_COMMAND(EVT_ID, wxEVT_COMMAND_TEXT_UPDATED, GUIThread_Dialog::MyEventHandler)
So, when I use the event handler, the function

Code: Select all

void GUIThread_Dialog::MyEventHandler(wxCommandEvent& event)
{
//do something 
}
will immediately do its task, no matter which thread sent the event to be processed.

To be as clear as possible, regardless of using

Code: Select all

m_parent->GetEventHandler()->AddPendingEvent(eventToBeProcessed);
or

Code: Select all

m_parent->GetEventHandler()->ProcessEvent(eventToBeProcessed);
the event handler which will actually "do something" is the one of the main thread right?

the only difference, if I understand correctly, is about "when" the event is supposed to be processed
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Events & secondary threads

Post by doublemax »

So, in order to avoid any misunderstanding, the event handler is immediately called by the worker/secondary thread (= the one you named the caller) but the event is processed by the main thread, right?
No. "Calling an event handler" and "Handling an event" mean the same in this context. If you call ProcessEvent from a worker thread, the event will be handled (= its event handler will be called) immediately in the same thread context.

Therefore you should always use QueueEvent or AddPendingEvent from worker threads.
Use the source, Luke!
wxJack
Experienced Solver
Experienced Solver
Posts: 83
Joined: Wed Jun 20, 2018 8:06 am

Re: Events & secondary threads

Post by wxJack »

No. "Calling an event handler" and "Handling an event" mean the same in this context. If you call ProcessEvent from a worker thread, the event will be handled (= its event handler will be called) immediately in the same thread context.
Thanks for your reply!
So you're telling me that, regardless of how the event handler is defined (a GUI function or a function of a worker thread, no matter), using ProcessEvent from a worker thread means that this secondary thread will process the event?

I mean...
Let's say that this function :
void GUIThread_Dialog::MyEventHandler(wxCommandEvent& event)
{
//do something
}

modifies the GUI (i.e. updates a wxListCtrl)...using ProcessEvent from a secondary thread means that a secondary threads touches the GUI?
(And unfortunately I know that this is not recommended!).

For this reason you're suggesting that I use these instead...
Therefore you should always use QueueEvent or AddPendingEvent from worker threads.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Events & secondary threads

Post by doublemax »

So you're telling me that, regardless of how the event handler is defined (a GUI function or a function of a worker thread, no matter), using ProcessEvent from a worker thread means that this secondary thread will process the event?
Yes.
Therefore you should always use QueueEvent or AddPendingEvent from worker threads.
Yes.
Use the source, Luke!
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: Events & secondary threads

Post by alys666 »

wxJack wrote: Tue May 28, 2019 3:05 pm
No. "Calling an event handler" and "Handling an event" mean the same in this context. If you call ProcessEvent from a worker thread, the event will be handled (= its event handler will be called) immediately in the same thread context.
Thanks for your reply!
So you're telling me that, regardless of how the event handler is defined (a GUI function or a function of a worker thread, no matter), using ProcessEvent from a worker thread means that this secondary thread will process the event?

I mean...
Let's say that this function :
void GUIThread_Dialog::MyEventHandler(wxCommandEvent& event)
{
//do something
}

modifies the GUI (i.e. updates a wxListCtrl)...using ProcessEvent from a secondary thread means that a secondary threads touches the GUI?
(And unfortunately I know that this is not recommended!).

For this reason you're suggesting that I use these instead...
Therefore you should always use QueueEvent or AddPendingEvent from worker threads.
processing of event means searching an appropriate user or system hook, bind to this wxEventHandler, and call it with given event. this must be done by thread-receiver. thread-sender must only put an event to message queue of some wxEventHandler instance.
if sender calls ProcessEvent of wxEventHandler, which another thread uses for incoming events, you'll ruin you system. it's not the business of sender.
ubuntu 20.04, wxWidgets 3.2.1
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: Events & secondary threads

Post by Manolo »

A thread executes code, no matter where it's written. So, calling a GUI function or event-handler or whatever from a thread will execute that code as if was written "inside" the thread's code.

An event handler receives events, comming from the OS or from [your] code, and stores them in a list. Latter, the list is queried and each event-reactor is excuted. The difference is what thread executes the "reactor". ProccessEvent can be called from any thread and so executed inmediately.
The event-loop that wx uses internally in the main thread will query each event handler for not-proccesed-yet events, and call each reactor.

AddPendingEvent has the issue of wxString is not thread safe. For worker threads sending messages best use QueueEvent. See https://docs.wxwidgets.org/trunk/overview_events.html
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: Events & secondary threads

Post by alys666 »

it's good to mention, that for user events better to use wxThreadEvent.
https://docs.wxwidgets.org/3.0/classwx_ ... event.html
ubuntu 20.04, wxWidgets 3.2.1
User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2409
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania

Re: Events & secondary threads

Post by evstevemd »

Since the OP seems to be newbee, I will post sample code (no complete but to give idea)

Code: Select all

//create wxEvtHandler subclass so that it receives events. It might be wxFrame or wxDialog since they subclass wxEvtHandler
//bind your event to handler
class HandlerClass : public wxEvtHandler
{
//.......
    public:
        HandlerClass()
        {
            Bind(wxEVT_THREAD, &HandlerClass::OnThreadMessages, this);
        }

    OnThreadMessages(wxThreadEvent& e) { // do something with event }
};



MyThread *thread = new MyThread(handler) // pass wxEvtHandler that will receive events

//in executing thread, post back events
MyThread::Entry()
{
     //post an event
     wxThreadEvent *e = new wxThreadEvent(...)
     // Set payload to event
     //Post event
     wxQueueEvent(m_handler, e);
}
It's not intended to be complete but rather give an idea...!
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: Events & secondary threads

Post by alys666 »

evstevemd wrote: Tue May 28, 2019 5:37 pm Since the OP seems to be newbee, I will post sample code (no complete but to give idea)

Code: Select all

//create wxEvtHandler subclass so that it receives events. It might be wxFrame or wxDialog since they subclass wxEvtHandler
//bind your event to handler
class HandlerClass : public wxEvtHandler
{
//.......
    public:
        HandlerClass()
        {
            Bind(wxEVT_THREAD, &HandlerClass::OnThreadMessages, this);
        }

    OnThreadMessages(wxThreadEvent& e) { // do something with event }
};



MyThread *thread = new MyThread(handler) // pass wxEvtHandler that will receive events

//in executing thread, post back events
MyThread::Entry()
{
     //post an event
     wxThreadEvent *e = new wxThreadEvent(...)
     // Set payload to event
     //Post event
     wxQueueEvent(m_handler, e);
}
It's not intended to be complete but rather give an idea...!
imho, it's excessive to create your custom eventhandler.
wxWindow already inherits from wxEventHandler, so you can just post messages to your MainFrame, and define there needed hooks(as i do :)). moreover you can post a message to any instance of wxWindow, or derivatives.
if you want to post messages between user threads, better to use wxMessageQueue class, as it was discussed a lot, not long ago.
wxEventHandler basically is just a wxMessageQueue with additional code of events dispatching to user hooks.
ubuntu 20.04, wxWidgets 3.2.1
User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2409
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania

Re: Events & secondary threads

Post by evstevemd »

alys666 wrote: Tue May 28, 2019 6:28 pm imho, it's excessive to create your custom eventhandler.
wxWindow already inherits from wxEventHandler, so you can just post messages to your MainFrame, and define there needed hooks(as i do :)). moreover you can post a message to any instance of wxWindow, or derivatives.
if you want to post messages between user threads, better to use wxMessageQueue class, as it was discussed a lot, not long ago.
wxEventHandler basically is just a wxMessageQueue with additional code of events dispatching to user hooks.
Well, I said what you just said. Thank you for expanding it ;)

here it is
//create wxEvtHandler subclass so that it receives events. It might be wxFrame or wxDialog since they subclass wxEvtHandle
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
wxJack
Experienced Solver
Experienced Solver
Posts: 83
Joined: Wed Jun 20, 2018 8:06 am

Re: Events & secondary threads

Post by wxJack »

Guys, many thanks for your answers.
Really appreciate it!
AddPendingEvent has the issue of wxString is not thread safe. For worker threads sending messages best use QueueEvent
What do you mean saying that "AddPendingEvent has the issue of wxString is not thread safe"? Could you please explain this concept?

thanks in advance

PS: is that, looking at the documentation, I found this
" For posting events to a certain event handler there are two possibilities: using wxEvtHandler::AddPendingEvent or using wxEvtHandler::QueueEvent. Basically you will need to use the latter when doing inter-thread communication; when you use only the main thread you can also safely use the former "
Since I only need a communication from secondary thread to the main one only, I'd like to use AddPendingEvent. Do you recommend not using it?
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Events & secondary threads

Post by doublemax »

Manolo is right, QueueEvent is better and you should use it (at least if you transmit strings with the event).

Regarding the thread safety of strings: Strings in wxWidgets can be (depending on the platform and compilation options) reference counted with copy-on-write. That means if you assign a wxString to another wxString, the actual memory block where the characters are stored, will be shared by the two wxString objects. And only when you modify one of them, new memory for the new content will be allocated. But this operation is not thread-safe, meaning that if two threads were to modify these two strings (almost) at the same time, bad things can happen :)

However, using QueueEvent will not solve the problem about wxString not being thread-safe. You'll need wxThreadEvent instead of wx[Command]Event for that.
Use the source, Luke!
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: Events & secondary threads

Post by alys666 »

doublemax wrote: Wed May 29, 2019 1:30 pm Regarding the thread safety of strings: Strings in wxWidgets can be (depending on the platform and compilation options) reference counted with copy-on-write. That means if you assign a wxString to another wxString, the actual memory block where the characters are stored, will be shared by the two wxString objects. And only when you modify one of them, new memory for the new content will be allocated. But this operation is not thread-safe, meaning that if two threads were to modify these two strings (almost) at the same time, bad things can happen :)
imho even ref counting in wxString is not thread safe, else you could share const wxString among threads(do not remember such mentioning in documentation).
ubuntu 20.04, wxWidgets 3.2.1
Post Reply