I have a custom scene manager, which apart from loading scenes calls some events for me. I want it to fully load a scene, before it starts loading another one, so I added a lock. I'm using Monitor because I want to enter the lock in OnLoadScene() and exit it in LoadSceneAsync() and this wouldn't be possible with the lock() {} syntax, because LoadSceneAsync() is called as a Coroutine (asynchronously). I found the Monitor syntax here: C# manual lock/unlock.
Here is the code:
public class CustomSceneManager : Singleton<CustomSceneManager>
{
    public delegate void SceneChange(string sceneName);
    public event SceneChange LoadScene;
    public event SceneChange UnloadScene;
    private static readonly object LoadSceneLock = new object();
    private IEnumerator LoadSceneAsync(string sceneName)
    {
        var asyncLoadLevel = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
        while (!asyncLoadLevel.isDone)
        {
            yield return null;
        }
        Debug.Log($"Finished loading: {sceneName}");
        LoadScene?.Invoke(sceneName);
        Monitor.Exit(LoadSceneLock); // exit lock
    }
    public void OnLoadScene(string newSceneName)
    {
        Monitor.Enter(LoadSceneLock); // enter lock
        Debug.Log($"Started loading: {newSceneName}");
        UnloadScene?.Invoke(newSceneName);
        StartCoroutine(LoadSceneAsync(newSceneName));
    }
}
The issue is that it doesn't work as I expect it to. This is how my logs look:
Started loading: scene_1
Started loading: scene_2
Finished loading: scene_1
Finished loading: scene_2
Am I using the lock incorrectly?