我正在通过命名管道与另一个进程通信。管道服务器用C#实现,客户端用C语言编写,服务器是WPF应用程序。
我需要创建一个NamedPipeServerStream
,并等待(同步)1秒才能连接到客户端。然后我需要知道客户是否有关联。
由于NamedPipeServerStream
取消/超时客户端连接的唯一方法是通过它的异步WaitForConnectionAsync
方法(这需要一个CancellationToken
)来实现我认为是同步等待的方法,如下所示:
public bool WaitOneSecondForClientConnect()
{
bool result = false;
try
{
result = WaitForConnectionAsyncSyncWrapper().Result;
}
catch (AggregateException e)
{
log.Write("Error waiting for pipe client connect: " + e.InnerException.Message);
}
return result;
}
private async Task<bool> WaitForConnectionAsyncSyncWrapper()
{
CancellationTokenSource cts = new CancellationTokenSource(1000);
await pipe.WaitForConnectionAsync(cts.Token);
return pipe.IsConnected;
}
管道的定义如下:NamedPipeServerStream(pipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1, 1);
,WaitOneSecondForClientConnect()
函数在UI线程上运行。
应该使其同步的是访问它返回的异步WaitForConnectionAsyncSyncWrapper()
函数的Result
属性。为了访问结果,异步函数必须已经完全返回,并且它不能执行return pipe.IsConnected
行,直到函数在await pipe.WaitForConnectionAsync(cts.Token);
完成后才恢复。至少这是我的理解。
所以问题是:尽管客户端程序说它打开了我的服务器的管道(当然在上面的代码执行之前已经创建了),但是WaitOneSecondForClientConnect()
永远不会返回。如果我闯入服务器,它就在这条线上:result = WaitForConnectionAsyncSyncWrapper().Result;
。
因此,我猜它是在等待任务的结果可用,如果客户机在1秒内连接,它应该是pipe.IsConnected
的值;或者,如果由于令牌被取消(1秒后),当我访问AggregateException
时,它应该抛出一个AggregateException
。但它只是完全挂在地上。
另一方面,如果我在令牌启动前取消它(例如在调用Thread.Sleep(2000);
之前放置一个await pipe.WaitForConnectionAsync(cts.Token);
),那么连接就会被成功取消(我认为它甚至不会尝试启动,因为令牌已经被取消了)--访问Result
属性会抛出一个AggregateException
等等.
有几件事要注意。
WaitOneSecondForClientConnect()
的内容替换为标准的同步pipe.WaitForConnection();
,它每次都能工作-即客户端连接,函数返回。工作的测试代码:
var pipe = new NamedPipeServerStream("SemiUsefulPipe_" + pid.ToString() + "ctest", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1, 1);
// ... dll containing pipe client is injected in client process at this point.
try
{
var result = ConnectAsync(pipe).Result;
}
catch (AggregateException)
{
Console.WriteLine("Connection failed.");
}
..。
private static async Task<bool> ConnectAsync(NamedPipeServerStream pipe)
{
CancellationTokenSource cts = new CancellationTokenSource(1000);
await pipe.WaitForConnectionAsync(cts.Token);
return pipe.IsConnected;
}
发布于 2015-09-10 21:38:38
您不能像这样混合异步和非异步方法。正在发生的事情是,您的WaitOneSecondForClientConnect
方法正在等待WaitForConnectionAsyncSyncWrapper
方法的完成。但那家伙需要它的调用线程是自由的,这样它才能重新补充原来的上下文。所以你刚刚造成了一个僵局。有关详细信息,请参阅https://msdn.microsoft.com/en-us/magazine/jj991977.aspx。
相反,您需要一直走下去。
public async Task<bool> WaitOneSecondForClientConnect()
{
bool result = false;
try
{
result = await WaitForConnectionAsyncSyncWrapper();
}
catch (Exception e)
{
log.Write("Error waiting for pipe client connect: " + e.Message);
}
return result;
}
https://stackoverflow.com/questions/32511714
复制相似问题