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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions