1

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?

Wojtek Wencel
  • 2,257
  • 6
  • 31
  • 65
  • I think you can just use a bool here, the only work being done on other threads is the async load, but you're veryifing if it's done in the main thread. – mcrvaz May 15 '21 at 17:28
  • @mcrvaz I changed the `object` to `bool` but I still have the same issue. – Wojtek Wencel May 15 '21 at 17:53
  • Yes, I mean that you don't have to use a Monitor, just a `bool inUse` should be just fine. – mcrvaz May 15 '21 at 18:00
  • @mcrvaz But I need a blocking call so when I call `OnLoadScene()` consecutively all calls will be executed one after another. Can I achieve this with a simple flag? – Wojtek Wencel May 15 '21 at 18:03
  • Sorry, I tought you needed only to prevent the call. This isn't possible with a simple flag. I was not able to reproduce your expected behaviour with Monitor, but since it blocks the thread it's monitoring, I doubt it would be useful in this case. I would say the easiest approach here would be to create a Queue with your load routines. – mcrvaz May 16 '21 at 00:10
  • By not useful I mean that it would block the Unity main thread and the loading would never complete. If you started the monitor from another thread maybe it could work, but then you'd have to dodge around Unity limitations from being acessed by external threads. – mcrvaz May 16 '21 at 00:27

0 Answers0