Advanced Question InitModule deadlock

AeroSpatial

New member
Joined
Aug 2, 2018
Messages
4
Reaction score
0
Points
0
The following module, in the InitModule implementation, creates a thread
and then waits for it to begin execution.

This deadlocks when Orbiter tries to load it.

Code:
int g_thread = 0;

DWORD WINAPI ThreadBody(LPVOID lpParam) {
	g_thread = 1;
	return 0;
}

DLLCLBK void InitModule(HINSTANCE hDLL)
{
	CreateThread(0, 0, ThreadBody, 0, 0, 0);
	while (!g_thread);
}

Why does this happen? There's no warning in the API documentation to be careful with threads in InitModule, unlike the well-known warnings for DLL entry points.
 

dbeachy1

O-F Administrator
Administrator
Orbiter Contributor
Addon Developer
Donator
Beta Tester
Joined
Jan 14, 2008
Messages
9,217
Reaction score
1,563
Points
203
Location
VA
Website
alteaaerospace.com
Preferred Pronouns
he/him
One problem is that you should declare g_thread to be volatile so the compiler knows that its value could be changed by another thread and should therefore be re-read from memory each loop (as opposed to being cached in a CPU register).

However, a better, more efficient way to handle that rather than spinning at 100% CPU polling a volatile global variable would be to use WaitForSingleObject (set the object in your thread and wait for it in your main thread). However, why do you need to wait for the thread to start before continuing in the main thread? Normally you should only need to wait (via EnterCriticalSection, LeaveCriticalSection, WaitForSingleObject, etc.) when sending shared data to or reading shared data from the thread. More information is here.

And :welcome: to Orbiter-Forum!
:cheers:
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,875
Reaction score
2,129
Points
203
Location
between the planets
May I ask for the reason to start a new thread in InitModule? That seems to suggest that the threads lifetime is the same as the entire module, which is somewhat unusual. There are valid use-cases for this, I'd just like to make sure that you have one of them and are not trying to thread an operation that relies on synchronisation with the orbiter core, which is a lot more common.
 

AeroSpatial

New member
Joined
Aug 2, 2018
Messages
4
Reaction score
0
Points
0
This is just a minimal example to recreate the problem. What I was actually doing was calling SDL_Init from the SDL library, which has its own reasons for creating a thread and uses proper synchronisation techniques.

My point is: deadlock is expected if you create a thread in a DLL entry point and wait on it. But InitModule isn't a DLL entry point, and there's no warning in the API documentation to be careful with creating threads. So:

1. Why is Orbiter calling InitModule in such a way to cause this kind of deadlock to be possible, and should it be doing this?

2. If there are good reasons for this to be the case, then warnings should be added to the API documentation. Although, given that most advice I can find on DLL entry points is "don't do anything in them", maybe InitModule should be removed entirely.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Why does this happen? There's no warning in the API documentation to be careful with threads in InitModule, unlike the well-known warnings for DLL entry points.

During OMP development - which is a mixed-mode assembly on the client side - I found the standard InitModule to suffer from the same problems as DLL entry points. I had to work around the well-known loader-lock when initiating managed objects, as well as found threads not started until after InitModule returned.

It seems to be the same with the somewhat new oapi::Module API, where code in the constructor shows similar problems.
 
Top