Skip to content

ObjectDisposedException Thrown When Disposing Subscription While Awaiting PublishAsync #17

@c3-hoge-fuga-piyo

Description

@c3-hoge-fuga-piyo

It might be necessary to check whether the object has already been disposed.

With Unity + ZeroMessenger + R3 (CancellationToken based lifetime management), implementations like the following are common, so it's likely necessary to avoid depending on execution order.

CancellationToken lifetimeToken = ...;

broker = new MessageBroker<T>();
broker.RegisterTo(lifetimeToken);

broker.SubscibeAwait(...).RegisterTo(lifetimeToken); // RegisterTo == CancellationToken.Register

Unity 6000.0.45f1

using UnityEngine;

using System.Threading;

using ZeroMessenger;

struct Message
{
}

sealed class Test : MonoBehaviour
{
    async void Start()
    {
        var cancellationToken = this.destroyCancellationToken;

        var broker = new MessageBroker<Message>();
        cancellationToken.Register(broker.Dispose);

        var subscription = broker.SubscribeAwait(async (_, ct) => {
            // Long-running operation
            while (!ct.IsCancellationRequested)
            {
                await Awaitable.NextFrameAsync(ct);
            }
        });
        cancellationToken.Register(subscription.Dispose); // Callbacks registered via CancellationToken.Register appear to be invoked in the reverse order of registration.

        await broker.PublishAsync(default, cancellationToken: cancellationToken);
    }
}
ObjectDisposedException: The semaphore has been disposed.
System.Threading.SemaphoreSlim.CheckDispose () (at <27bd554a9f0e46179afd19da1336e638>:0)
System.Threading.SemaphoreSlim.Release (System.Int32 releaseCount) (at <27bd554a9f0e46179afd19da1336e638>:0)
System.Threading.SemaphoreSlim.Release () (at <27bd554a9f0e46179afd19da1336e638>:0)
ZeroMessenger.SequentialAsyncMessageHandler`1[T].HandleAsyncCore (T message, System.Threading.CancellationToken cancellationToken) (at <35f312125e30466b9536671d1da5e9f6>:0)
ZeroMessenger.Internal.ValueTaskWhenAll`1+AwaiterNode[T].OnCompleted () (at <35f312125e30466b9536671d1da5e9f6>:0)
--- End of stack trace from previous location where exception was thrown ---
ZeroMessenger.Internal.ValueTaskWhenAll`1[T].GetResult () (at <35f312125e30466b9536671d1da5e9f6>:0)
ZeroMessenger.MessageBroker`1[T].PublishAsync (T message, ZeroMessenger.AsyncPublishStrategy publishStrategy, System.Threading.CancellationToken cancellationToken) (at <35f312125e30466b9536671d1da5e9f6>:0)
Test.Start () (at Assets/Scripts/Test.cs:35)
System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) (at <27bd554a9f0e46179afd19da1336e638>:0)
UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at /Users/bokken/build/output/unity/unity/Runtime/Export/Scripting/UnitySynchronizationContext.cs:156)
UnityEngine.UnitySynchronizationContext.Exec () (at /Users/bokken/build/output/unity/unity/Runtime/Export/Scripting/UnitySynchronizationContext.cs:84)
UnityEngine.UnitySynchronizationContext.ExecuteTasks () (at /Users/bokken/build/output/unity/unity/Runtime/Export/Scripting/UnitySynchronizationContext.cs:110)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions