"Main thread" vs. other threads 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.
Ksawery
Experienced Solver
Experienced Solver
Posts: 83
Joined: Thu Jul 25, 2019 12:31 pm

"Main thread" vs. other threads

Post by Ksawery »

I have a quick question regarding multithreading inside a wxWidgets application. As I understand, there is a "main thread" in the application, which procedurally creates and manages the application. My question is: what would happen if an infinite while loop was placed in two different frames simulatenously? Are they both managed by the same, main thread? Would the application effectively hang and not respond to any user events (e.g. button clicks), until the loops were broken? Do infinite loops inside the application always need an additional thread, such wxTthread or wxThreadHelper?

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

Re: "Main thread" vs. other threads

Post by alys666 »

even one infinite loop in any method called from main thread(which dispatches events, redraws and calles user handlers) will block it. because processor will infinitely execute the loop without exit, as programmer wrote this code. processor is just a machine, executing instructions. if he met infinite loop, he will sit inside it forever.
ubuntu 20.04, wxWidgets 3.2.1
Ksawery
Experienced Solver
Experienced Solver
Posts: 83
Joined: Thu Jul 25, 2019 12:31 pm

Re: "Main thread" vs. other threads

Post by Ksawery »

Ok, thanks. Two more questions that I have:

1. Is there a healthy limit to the number of threads used in my application.
2. Is it ok to use wxThread and wxThreadHelper classes alongside each other?

My application currently uses 3 wxThreads and 4 wxThreadHelpers. The 3 wxThreads are created within a single class, while the 4 wxThreadHelpers are created in 2 separate frames (2 in each). All threads have shared access to certain memory locations, protected with the same Critical Section lock. Unfortunately my application hangs at one point (when opening the second frame that uses helper threads), and I'm trying to identify the root of the problem (i'm not sure if it's caused by multithreading). I may have overdone it with the number of threads and shared memory access. Perhaps I should limit everything to the 3 wxThreads, and substitute the helper threads with events sent from the 3 wxThreads?

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

Re: "Main thread" vs. other threads

Post by alys666 »

abstract threading model has not limit for of threads.
thread is just an independent activity, executed in parallel with other activities.
but in reality every real thread consumes:
1. memory, because has separate stack.
2. os resources(depends on os implementation). usually OS has limit for threads amount per application, it's thousands.
normally application does not need thousands of threads, at least such a program architecture looks doubtful.
zillions of parallel activities are needed only for some abstract modelling of real world, where zillions of things live their own independent lives.
to understand how many threads your app needs, just draw on paper - which independent activities live in your tasks.
for example.
task reads some input from user, makes some calculations and sends data to network.
here are 3 activity max. task could have 3 threads:
thread 1 - reads user input and sends it to thread 2 data queue.
thread 2 - gets data from queue, is doing some calculations and sends result to thread 3 data queue
thread 3 - gets results from queue and sends it network interface.
ubuntu 20.04, wxWidgets 3.2.1
Ksawery
Experienced Solver
Experienced Solver
Posts: 83
Joined: Thu Jul 25, 2019 12:31 pm

Re: "Main thread" vs. other threads

Post by Ksawery »

Thanks for your reply, that's very helpful. My use of threads is as follows:

wxThread 1: Modbus RTU Communication (Serial Port 1)
wxThread 2: Modbus RTU Communication (Serial Port 2)
wxThread 3: Modbus TCP/IP Communication (Ethernet)

All three threads interact with the same data structure, so critical sections are used. The same data structure is read by the following helper threads (again, the same critical section is used to protect the Modbus data structure):

wxThreadHelper 1: Update display in Frame 1.
wxThreadHelper 2: Update display in Frame 2.
wxThreadHelper 3: Update display in Frame 3.
wxThreadHelper 4: Update display in Frame 4.

These threads are created in the same order as above. Each helper thread "lives" within it's respective frame. The application hangs upon creating Frame 2. It doesn't freeze entirely, something is happening in the background, but i'm not sure what. I'm also not sure how to diagnose the problem. When pausing the application in debugging mode, it never pauses inside my code. Here is the information I recieve:

Code: Select all

PomiarWiazki_Gateway [C/C++ Application]	
	PomiarWiazki_Gateway [14738] [cores: 0,1,3]	
		Thread #1 [PomiarWiazki_Ga] 14738 [core: 0] (Suspended : Signal : SIGINT:Interrupt)	
			__lll_lock_wait() at lowlevellock.S:135 0x7ffff648b10d	
			__GI___pthread_mutex_lock() at pthread_mutex_lock.c:113 0x7ffff6484098	
			wxMutexInternal::Lock() at threadpsx.cpp:274 0x7ffff6db1b2b	
			wxMutex::Lock() at thrimpl.cpp:43 0x7ffff6db91b8	
			wxCriticalSection::Enter() at thread.h:291 0x55555557cb48	
			wxCriticalSectionLocker::wxCriticalSectionLocker() at thread.h:307 0x55555557cb92	
			cMain::OnThreadUpdate() at cMain.cpp:297 0x555555584a6a	
			wxAppConsoleBase::HandleEvent() at appbase.cpp:657 0x7ffff6cadbfc	
			wxAppConsoleBase::CallEventHandler() at appbase.cpp:669 0x7ffff6cadc70	
			wxEvtHandler::ProcessEventIfMatchesId() at event.cpp:1,396 0x7ffff6dd6d7c	
			<...more frames...>	
		Thread #2 [gmain] 14755 [core: 0] (Suspended : Container)	
		Thread #3 [gdbus] 14756 [core: 1] (Suspended : Container)	
		Thread #4 [PomiarWiazki_Ga] 14757 [core: 3] (Suspended : Container)	
		Thread #5 [PomiarWiazki_Ga] 14758 [core: 1] (Suspended : Container)	
		Thread #6 [PomiarWiazki_Ga] 14759 [core: 1] (Suspended : Container)	
		Thread #7 [PomiarWiazki_Ga] 14760 [core: 3] (Suspended : Container)	
		Thread #8 [PomiarWiazki_Ga] 14761 [core: 3] (Suspended : Container)	
	gdb (8.1.0.20180409)	
Maybe something to do with conflicting critical sections?

Any help would be appreciated.

Regards,
Ksawery
Last edited by Ksawery on Wed Oct 16, 2019 12:28 pm, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: "Main thread" vs. other threads

Post by doublemax »

Most likely there is some kind of deadlock, but without knowing what the threads do and how they interact with each other it's hard to tell why and where.

The 4 wxThreadHelpers are suspicious, especially since you wrote they "update display". Even when using a wxThreadHelper, you are not allowed to access gui elements from within the worker thread. As GUI updates usually don't need a high frequency anyway, i always use a timer instead of sending events from the worker to the main thread. Just have a timer at 10-20Hz and in the event handler get information from the thread(s) and update the controls.
Use the source, Luke!
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: "Main thread" vs. other threads

Post by alys666 »

for first look according to debugger output
you're breaked in wait in line of your code
cMain::OnThreadUpdate() at cMain.cpp:297
in trying to lock some critical section.
all other threads are suspended and are not active, and are not waiting.
so problem looks like some thread locked this section and did not unlock it. and somehow was suspened.
but the thread 1 is trying to lock this abandoned section.
Last edited by alys666 on Wed Oct 16, 2019 12:50 pm, edited 1 time in total.
ubuntu 20.04, wxWidgets 3.2.1
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: "Main thread" vs. other threads

Post by alys666 »

also when one thread is waiting, but others are resumed... it looks strange for me.
all threads in multithreading model must wait something if they are not running now, or run crazy infinitely.
how your treads are resumed? what they are waiting for? how they activate later?
ubuntu 20.04, wxWidgets 3.2.1
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: "Main thread" vs. other threads

Post by alys666 »

it looks like some thread locked section, and was somehow suspended... via maybe sleep(..) or something.
ubuntu 20.04, wxWidgets 3.2.1
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: "Main thread" vs. other threads

Post by alys666 »

you must look at your multithreading system as a set of threads(activities) and message flows between them.
if you implemented correctly this message flows(using thread safe queues), and properly implemented thread's code - everything will work like a charm.
ubuntu 20.04, wxWidgets 3.2.1
Ksawery
Experienced Solver
Experienced Solver
Posts: 83
Joined: Thu Jul 25, 2019 12:31 pm

Re: "Main thread" vs. other threads

Post by Ksawery »

Thanks again for your replies. So what seems to be happening, is that the application eventually starts, albeit very slowly. It's then very unresponsive, and has a very high memory/CPU usage. So there's definitely something wrong with the way that I implemented multithreading. I assumed that the threads would execute in order, and work nicely together, however it seems that they are insanely competing for resources, slowing down the whole application. Each thread is an infinite loop, responsible either for Modbus communcation or displaying the data on screen.

As per doublemax's suggestion, would adding delays help alleviate these issues, or is there a better way that I'm not aware of? I'd prefer the app to work as quickly as possible. Perhaps i'm using the critical sections incorrectly? Could the wxThread and wxThreadHelper be conflicting in some manner?
The 4 wxThreadHelpers are suspicious, especially since you wrote they "update display". Even when using a wxThreadHelper, you are not allowed to access gui elements from within the worker thread. As GUI updates usually don't need a high frequency anyway, i always use a timer instead of sending events from the worker to the main thread. Just have a timer at 10-20Hz and in the event handler get information from the thread(s) and update the controls.
@doublemax As per the wxThreadHelper class reference, I never call GUI elements from the threads themselves, only from the event handlers, triggered on each iteration of the threads.
you must look at your multithreading system as a set of threads(activities) and message flows between them.
if you implemented correctly this message flows(using thread safe queues), and properly implemented thread's code - everything will work like a charm.
What are thread safe queues?

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

Re: "Main thread" vs. other threads

Post by alys666 »

thread safe queues template in wxWidgets -
https://docs.wxwidgets.org/trunk/classw ... _01_4.html
also wxEventHandler class, the base class for wxWindow already has a thread-safe queue, but for wxThreadMessage class.
you can inherit from wxThreadMessage your custom class and send messages from custom threads to your frames, for example - mainframe. I do so in my design.
I never used wxTreadHelper, it's something excessive for my academic paradigm :)
ubuntu 20.04, wxWidgets 3.2.1
alys666
Super wx Problem Solver
Super wx Problem Solver
Posts: 329
Joined: Tue Oct 18, 2016 2:31 pm

Re: "Main thread" vs. other threads

Post by alys666 »

normally thread must wait some event for some timeout, and if not awaited - check some variable, which says - it's time to exit.
so pseudocode is

Code: Select all

while(!_exit_now){
	if(waitEventOrMessageOnQueueDuring(Xmillseconds)){
		getDataFromQueue(...);
		handleData(...);
		sendMessageWithResultToAnotherQueue(...); //if needed
	}
}
there must not be any sleeps, explicit suspends or something...
ubuntu 20.04, wxWidgets 3.2.1
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: "Main thread" vs. other threads

Post by doublemax »

only from the event handlers, triggered on each iteration of the threads.
How often is that? My guess it's far too often.

If you have an "infinite" loop in a thread, this will of course cause 100% CPU load on one CPU core. If you're polling in a thread, you should call wxThread::Sleep(1) on each iteration. Sending events to the main thread should happen much less frequent, maybe 10-20 per second at max.
Use the source, Luke!
Ksawery
Experienced Solver
Experienced Solver
Posts: 83
Joined: Thu Jul 25, 2019 12:31 pm

Re: "Main thread" vs. other threads

Post by Ksawery »

Thanks for your replies. It does indeed seem that I occupied all available cores with the threads - and then some. So obviously my application worked very slowly. I'm new to multi-threading, so i'm still learning the best practices.

I like the suggestion of sending events to the main thread, from the 2 wxThreads that I use for Modbus RTU communication. It makes much more sense to update the displays only when new data is available. I will also add 1s delays to both threads, as new data will not be available faster than that. I'll skip using the 4 helper threads. I will need to figure out how to do all that tomorrow.
Sending events to the main thread should happen much less frequent, maybe 10-20 per second at max.
I think I will need to trigger a maximum of 4 events in the main thread per second, so I should be ok?

Another question: if I add delays to my threads, will they still occupy 100% of a CPU core each? Should I limit the number of "infinite" threads to as few as possible?

Regards,
Ksawery
Post Reply