wxThread and wxQueueEvent

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
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

wxThread and wxQueueEvent

Post by dualband »

Hi

I use wxWidgets 3.1.4 and Windows10
I was trying to use wxThread based on the example taken from https://docs.wxwidgets.org/trunk/classwx_thread.html
I have fixed several things according to some of the conversations in the forum and I was able to compile and run the program.
However, the main thread(GUI) cannot catch the event that should have been posted by the second thread.
I have been stuck for several days. Hope someone in the forum can help.

I have attached a toy project "event_debug.zip" just simply shows the parts of the codes I have problem.

The code below supposed to send an update event every time it finish connecting to server (here, it just waits for two seconds). And, after it finishs five times of connections, it supposed to send a complete event. But, in the main thread, it never catches the event.

Code: Select all

wxThread::ExitCode myThread::Entry()
{
	wxLogMessage("======= Start of C++ Socket Client Testing Thread ========");
	for (int i = 0; i < 5; i++)
	{
		wxLogMessage("Connecting to server... Attempt %u\n", i);
		Sleep(2000);
		wxQueueEvent(m_pHandler->GetEventHandler(), new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
	}
	wxLogMessage("======== End of C++ Socket Client Testing Thread ========");
	wxQueueEvent(m_pHandler->GetEventHandler(), new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
	return (wxThread::ExitCode)0;     // success
}
I have declared and defined the new two event types in the main thread myFrame.cpp

Code: Select all

// declare a new type of event, to be used by our MyThread class:
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);

wxBEGIN_EVENT_TABLE(myFrame, wxFrame)

	EVT_BUTTON(wxID_BTN_CONNECT, myFrame::OnBtnConnect)

	EVT_THREAD(wxEVT_COMMAND_MYTHREAD_UPDATE, myFrame::OnThreadUpdate)
	EVT_THREAD(wxEVT_COMMAND_MYTHREAD_COMPLETED, myFrame::OnThreadCompletion)

wxEND_EVENT_TABLE()

wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
In the codes below, it should print out the message when it receives the events. But, the codes never got exercised.

Code: Select all

void myFrame::OnThreadCompletion(wxThreadEvent&)
{
	wxLogMessage("============== MYFRAME: MyThread exited! ===============");
}

void myFrame::OnThreadUpdate(wxThreadEvent&)
{
	wxLogMessage("============== MYFRAME: MyThread update... ===============");
}

I also attached a screenshot for the result of the test program

Thanks for your help!
Attachments
Screenshot of result
Screenshot of result
screenshot.PNG (15.99 KiB) Viewed 2674 times
event_debug.zip
Visual studio project archive
(6.91 KiB) Downloaded 75 times
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxThread and wxQueueEvent

Post by New Pagodi »

I don't think the EVT_THREAD macro works with custom thread events. I think the event table macro needs to be something like this:

Code: Select all

wx__DECLARE_EVT1(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxID_ANY, wxThreadEventHandler(myFrame::OnThreadCompletion))
But I would recommend using Bind instead of event tables.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread and wxQueueEvent

Post by doublemax »

Unfortunately the sample code in the documentation is bad, it doesn't even compile with the latest wxWidgets version.

Like New Pagodi said:
Remove the entries in the static event table, instead add these two lines at the end of the myFrame ctor:

Code: Select all

Bind(wxEVT_COMMAND_MYTHREAD_UPDATE, &myFrame::OnThreadUpdate, this);
Bind(wxEVT_COMMAND_MYTHREAD_COMPLETED, &myFrame::OnThreadCompletion, this);
Use the source, Luke!
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

Re: wxThread and wxQueueEvent

Post by dualband »

Thank you both New Pagodi and doublemax!
The issue was resolved with your suggestions :)

Is there a way to request the corrections of the webpage https://docs.wxwidgets.org/trunk/classwx_thread.html
I am hoping no one will suffer the same problem as I did.

Thanks
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 357
Joined: Tue Jun 07, 2016 1:07 pm

Re: wxThread and wxQueueEvent

Post by Kvaz1r »

dualband wrote: Fri May 14, 2021 2:58 am Thank you both New Pagodi and doublemax!
The issue was resolved with your suggestions :)

Is there a way to request the corrections of the webpage https://docs.wxwidgets.org/trunk/classwx_thread.html
I am hoping no one will suffer the same problem as I did.

Thanks
You can fix it and propose patch - How to Contribute to wxWidgets or at least open a ticket - https://trac.wxwidgets.org
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

Re: wxThread and wxQueueEvent

Post by dualband »

Hi Kvaz1r

Thanks for the information.
I am not able to login to https://trac.wxwidgets.org with my ID/PASS in this forum.
Do I need to register a new ID to access trac.wxwidgets.org?

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

Re: wxThread and wxQueueEvent

Post by doublemax »

dualband wrote: Fri May 14, 2021 11:21 pm Do I need to register a new ID to access trac.wxwidgets.org?
Yes, that site is completely separate from this one.
Use the source, Luke!
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

Re: wxThread and wxQueueEvent

Post by dualband »

I encountered another issue when I was trying to close the GUI(main thread).
If I closed the GUI after the second thread is finished, everything looks great. But, if I closed the GUI while the second thread is still alive, memory leaks occur. I tried to fix this problem by closing the thread in the destructor ~myFrame() to make the second thread to exit graciously. But, it resulted an exception happened during the execution of the code m_pThread->Delete()

Code: Select all

myFrame::~myFrame()
{
	DoCloseThread();
}

Code: Select all

void myFrame::DoCloseThread()
{
	{
		wxCriticalSectionLocker enter(m_pThreadCS);
		if (m_pThread)         // does the thread still exist?
		{
			wxLogMessage("%%%%% MYFRAME: deleting thread %%%%%");
			if (m_pThread->Delete() != wxTHREAD_NO_ERROR)
				wxLogError("Can't delete the thread!");
		}
	}       // exit from the critical section to give the thread
			// the possibility to enter its destructor
			// (which is guarded with m_pThreadCS critical section!)
	while (1)
	{
		{ // was the ~MyThread() function executed?
			wxCriticalSectionLocker enter(m_pThreadCS);
			if (!m_pThread) break;
		}
		// wait for thread completion
		wxThread::This()->Sleep(1);
	}
	Destroy();
}
I put TestDestroy() in the second thread to exit the thread graciously

Code: Select all

wxThread::ExitCode myThread::Entry()
{
	//wxLogMessage("======= Start of C++ Socket Client Testing Thread ========");
	for (int i = 0; i < 5; i++)
	{
		if (TestDestroy())
			break;

		wxLogMessage("Connecting to server... Attempt %u\n", i);

		Sleep(2000);

		wxQueueEvent(m_pHandler->GetEventHandler(), new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
	}

	wxLogMessage("======== End of C++ Socket Client Testing Thread ========");

	wxQueueEvent(m_pHandler->GetEventHandler(), new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));

	return (wxThread::ExitCode)0;     // success
}
Is there any problem in my implementation?
I also attached the project in case you want to test it.

Thanks.
Attachments
event_debug2.zip
Exception happens when closing the GUI while the second thread is alive
(7.03 KiB) Downloaded 81 times
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxThread and wxQueueEvent

Post by New Pagodi »

I guess that's OK. Personally, I would use a semaphore or a condition variable to signal to the thread that it should end instead of calling Destroy. But that's mostly a matter of preference. I think calling Destroy and checking for it with TestDestroy should be reserved for exceptional circumstances.

But if that works for you, I think it should be OK.
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

Re: wxThread and wxQueueEvent

Post by dualband »

Maybe I didn't describe correctly. Error indeed happened in my implementation. I attached the screenshot of the error.
Just want to know if there is anything wrong in my codes. As my codes was taken from the example in https://docs.wxwidgets.org/trunk/classwx_thread.html
If there is any problem in that example, I can also track the issue in the ticket I am to file.

On the other hand, I tired to use a variable to signal the thread to exit as you mentioned and it works well.
Thanks for your help.
Attachments
error.PNG
error.PNG (10.28 KiB) Viewed 2520 times
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread and wxQueueEvent

Post by doublemax »

The assert just comes from a bad printf, in your case, this line:

Code: Select all

wxLogMessage("%%%%% MYFRAME: deleting thread %%%%%");
Apart from that, i'm not sure if executing the code in the dtor of the frame is not too late. Try moving it to a close event handler like in the sample.
Use the source, Luke!
dualband
Earned a small fee
Earned a small fee
Posts: 15
Joined: Fri Oct 16, 2020 11:53 pm

Re: wxThread and wxQueueEvent

Post by dualband »

I was not aware of the syntax error on wxLogMessage :(
You are right. Putting the code in destructor is too late. And, following the example codes is just perfect.
Thanks again for spending time helping me.
Post Reply