1
\$\begingroup\$

I'm building a wrapper around NamedPipeServerStream and NamedPipeClientStream. Currently my Connect() method on the Client looks like this:

    public async Task Connect(CancellationToken cancellationToken = default(CancellationToken))
    {
        var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _connectCancellationTokenSource.Token);

        await _pipe.ConnectAsync(cts.Token).ConfigureAwait(false);

        lock (_lock)
        {
            if (_pipe.IsConnected)
            {
                _connectCancellationTokenSource.Dispose();
                _connectCancellationTokenSource = null;
                _pipe.ReadMode = PipeTransmissionMode.Message;
                Connection.Set();
                Connected?.BeginInvoke(this, EventArgs.Empty, x => ((EventHandler)x.AsyncState).EndInvoke(x), Connected);

                BeginRead();
            }
        }
    }

and my Dispose(bool) like this:

    protected override void Dispose(bool disposing)
    {
        lock (_lock)
        {
            _connectCancellationTokenSource?.Cancel();
            base.Dispose(disposing);
        }
    }

with the base.Dispose(bool) looking like this:

    protected virtual void Dispose(bool disposing)
    {
        if (!disposing) return;

        Connection.Reset();
        _pipe.Dispose();
        Connection.Dispose();

        _disposed = true;
    }

Basically I can't invoke Dispose(bool) while the connection Task is still running and waiting for it to finish is not an option as it might literally run forever.

My workaround was to create a linked CancellationTokenSource and use its token as the CancellationToken for the Task, allowing me to cancel it myself on Dispose().

I then had a race condition where it was entirely possible that the client would connect and pass the if (_pipe.IsConnected) only to be disposed of immediately after, causing it to throw on BeginRead() (which also uses _pipe), hence the lock on both Connect() and Dispose()

However I'm not entirely sure that my approach is really all that sane, and looking for either some validation or ways I could improve this. I'm also concerned I might be putting a bit too much inside the lock...

\$\endgroup\$
  • \$\begingroup\$ What happens if you remove this ConfigureAwait(false); ? \$\endgroup\$ – John Peters Dec 14 '17 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.