Currently using Critical Section’s to sync global variables but getting thread hangs.
Once around a Glo:Thread = Start(SomeWindowlessProcessProcedure) and the other around the Glo:Thread at the end of the SomeWindowlessProcessProcedure to reset back to zero.
So only use a critical section in two places, but I’m getting a thread hang, so need to come up with another way to stop the procedure from just hanging mid code. Ironically it would hang on the GetThreadID api which I used to track threads in ProcessExplorer.
Even Microsoft suggest using a non shareable file instead of a mutex, which may be relevant now due to the speed of NVMe and SSD drives.
So in your experience, what would be the best way to sync non threaded global variables.
I’m also getting the impression, that on windows today under the hood, each new thread comes with a section of memory which mirrors the primary processes global variables, which would force the need for synching, perhaps as a result of multicore cpu’s.
Using a critical section around a thread start sounds dangerous and could lead to your hang.
I’d do a Loc:Thread = Start(x) followed by a Glo:Thread = Loc:Thread wrapped in a critical section.
Execution is not passed to the proc x until later so no race
If you MUST use nonthreaded global variables, how about
Create a global class
make the variables properties for the class
have the class expose setter/getter for each variable
within the class, use a critical section when you update the actual variable(s)
assuming Glo:Thread is a LONG then I don’t think you need to worry about a critical section as I believe processing on a long is atomic - so there cannot be a thread switch in the middle of an assign (unlike string variables for example).
It might be, but the non-threaded global long is behaving in such a way, that I’m left with the impression, that the main process (_main) has its “master copy” global variables, and then when a new thread is started, a copy of those globals is made which is part of the started thread process, which could explain the slowness seen when starting a thread, compared to a procedure hop.
Its at this point the globals can get out of synch.
Likewise if this started thread updates a global, its not reflected in the (_main) process globals straight away hence the need for some sort of syncher.
Behind the scenes, I think MS are starting a thread as a new process, as seen in task manager and other api’s, and copy the global variables to the started thread to mirror, so there is a newly created instance of global variables per new thread.
I think the reason for this is simply to make life easier for them (MS) when a started thread, runs on a different cpu or cpu core. Behind the scenes, MS then synch’s the unthreaded global variables at its leisure, but we can accelerate matters by using synchers like critical sections, mutexes and sempahores.
You can see this sort of behaviour on really slow machines like my DWP paid for £180 Lenovo laptop, you wont see it on a blazing fast 5.1Ghz desktop.
I’d love to, but I’m trying to reduce the overhead that comes with procedure hops, I know its only a few lines of assembler but I need to make this program as lightweight as possible.
It is, but I’ve managed to get a RegisterWindowMessageA and a SendMessageA subclass working across threads from thread 2, so I’ve been able to eliminate all the critical sections in the started thread (thread 3) that sets the global variable back to zero at the end of the procedure, which means I can now change the Glo:Thread to a Loc:Thread.
When its encountered, the SendMessageA jumps right back to the main frame subclass (thread 2) and processes the event/user message before returning back to the started thread (thread 3). I dont think I’m going to get it any quicker or using less code than that. But I’ve also had to remove the FrameExtension template, and roll my own Systray icon handling code as well, as the notify in it was causing problems by its nature of being LIFO and not FIFO.
So my understanding of the way it works is that Global Threaded Variables Are Global to the thread they are on, not the whole process. So there is no Synchronization just the value of the variable in that thread.
Global unthreaded variable are statically allocated and viewable across all threads.
It’s a little more complex than that and involves hardware and the various cache levels of the CPU. If a thread on a diffferent CPU alters unthreaded global it requires a dump and reload of the cache data across all CPU’s probably a dump of the execution pipeline as well. This can be amazingly expensive. Which is why windows tries to keep all threads on a single CPU if possible.
Starting a thread is also expensive, you need to init all the variables etc.
Critical section is needed because a thread switch can occur while a variable (usually a string r similar) is in the middle of being copied.
Global unthreaded variables exist in one place. There are no copies.
For the 11 step process involved in starting a new thread, see the Help. You definitely should not add a critical section to this process.
The time it takes to start a thread is dependent on the number of global THREADed objects , variables and structures. This also dictates the amount of RAM required by the thread.
All global threaded structures (like FILEs) need to be allocated and cleared. All global objects need to be CONSTRUCTed and so on. Global UNTHREADed incur no cost.
If you need a program which can start threads very quickly then you need to avoid all global threaded declarations. But this would be for a specific use case, not a Legacy or ABC app.
At the code level, false sharing is a special concern in the following cases:
• Global data variables and static data variables that are placed in the same cache line and are written by different
threads.
Facilitate compiler optimization by:
— Minimize use of global variables and pointers.