[Bug]: Thread Safety GetCurrentPosition GPS manager extension method
JVanloofsvelt opened this issue · comments
Component/Nuget
GPS or Geofencing (Shiny.Locations)
What operating system(s) are effected?
- iOS (13+ supported)
- Mac Catalyst
- Android (8+ supported)
- Windows (.NET 7 Target - only Core is currently supported, BLE is coming)
Version(s) of Operation Systems
Any
Hosting Model
- MAUI
- Native/Classic Xamarin
- Manual
Steps To Reproduce
Invoke IGpsManager.GetCurrentPosition() from two threads.
Expected Behavior
Invoking static IObservable<GpsReading> GetCurrentPosition(this IGpsManager gpsManager)
yiels a location or throws an exception. It does this by possibly starting the gps listener, and then stopping the listener once finished.
Actual Behavior
Despite the use of a semaphore a race condition appears to be possible: by looking at the code it seems like it releases the semaphore before stopping the GPS manager, meaning a second thread can invoke GetCurrentPosition() as well, starting the GPS manager, only for the first thread to continue with stopping the listener.
I think the semaphore should only be released after the gps manager is stopped.
Extension method here:
shiny/src/Shiny.Locations/Extensions.cs
Line 59 in 9d09a0a
...
}
finally
{
currentLocSemaphore.Release();
if (iStarted)
await gpsManager.StopListener().ConfigureAwait(false);
}
If I'm mistaken, I'm happy to hear why.
Exception or Log output
No response
Code Sample
No response
Code of Conduct
- I have supplied a reproducible sample that is NOT FROM THE SHINY SAMPLES!
- I am a Sponsor OR I am using the LATEST stable/beta version from nuget (v3.0 stable - ALPHAS are not taking issues - Sponsors can still send v2 issues)
- I am Sponsor OR My GitHub account is 30+ days old
- I understand that if I am checking these boxes and I am not actually following what they are saying, I will be removed from this repository!
This will be part of the next release. Honestly though, I wouldn't be hammering this method in any case. You are better to turn the listener on when you need it