我在NamedPipeServerStream
和NamedPipeClientStream
周围构建了一个包装器。目前,Connect()
上的Client
方法如下所示:
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();
}
}
}
和我的Dispose(bool)
是这样的:
protected override void Dispose(bool disposing)
{
lock (_lock)
{
_connectCancellationTokenSource?.Cancel();
base.Dispose(disposing);
}
}
base.Dispose(bool)
看起来像这样:
protected virtual void Dispose(bool disposing)
{
if (!disposing) return;
Connection.Reset();
_pipe.Dispose();
Connection.Dispose();
_disposed = true;
}
基本上,当连接任务仍然在运行并且等待它完成时,我无法调用Dispose(bool)
,因为它可能永远无法运行。
我的解决方法是创建一个链接的CancellationTokenSource
并将其标记用作CancellationToken
的{{1}},允许我自己在Task
上取消它。
然而,这创造了一种竞争条件,其中客户端完全有可能连接并输入Dispose()
仅在之后立即处置,导致它抛出if (_pipe.IsConnected)
(也使用{ {1}}),因此BeginRead()
和_pipe
上的lock
但是,我并不完全确定我的方法真的是那么理智,并且正在寻找一些验证或我可以改进的方法。我也担心我可能会在Connect()
...