gpt4 book ai didi

c# - 如何序列化对异步资源的访问?

转载 作者:可可西里 更新时间:2023-11-01 02:45:47 26 4
gpt4 key购买 nike

谁能为我指出以下问题的有效解决方案?

我正在处理的应用程序需要通过 TCP 与在另一个系统上运行的软件进行通信。我发送到该系统的一些请求可能需要很长时间才能完成(最多 15 秒)。

在我的应用程序中,我有许多线程,包括可以访问与远程系统通信的服务 的主 UI 线程。只有一个服务实例被所有线程访问。

我一次只需要处理一个请求,即它需要被序列化,否则 TCP 通信会发生不好的事情。

目前尝试的解决方案

最初我尝试使用带有静态对象的 lock() 来保护每个“命令”方法,如下所示:

lock (_cmdLock)
{
SetPosition(position);
}

但是我发现有时它不会释放锁,即使在远程系统和 TCP 通信上有超时。此外,如果两个调用来自同一个线程(例如,用户双击一个按钮),那么它将越过锁定 - 在再次阅读有关锁定的内容后,我知道同一个线程不会等待锁定。

然后我尝试使用 AutoResetEvents 一次只允许一个调用通过。但是如果没有锁定,它就不能与多线程一起工作。以下是我用来发送命令(从调用线程)和处理命令请求(在后台运行在它自己的线程上)的代码

   private static AutoResetEvent _cmdProcessorReadyEvent = new AutoResetEvent(false);
private static AutoResetEvent _resultAvailableEvent = new AutoResetEvent(false);
private static AutoResetEvent _sendCommandEvent = new AutoResetEvent(false);

// This method is called to send each command and can run on different threads
private bool SendCommand(Command cmd)
{
// Wait for processor thread to become ready for next cmd
if (_cmdProcessorReadyEvent.WaitOne(_timeoutSec + 500))
{
lock (_sendCmdLock)
{
_currentCommand = cmd;
}

// Tell the processor thread that there is a command present
_sendCommandEvent.Set();

// Wait for a result from the processor thread
if (!_resultAvailableEvent.WaitOne(_timeoutSec + 500))
_lastCommandResult.Timeout = true;

}
return _lastCommandResult.Success;
}

// This method runs in a background thread while the app is running
private void ProcessCommand()
{
try
{
do
{
// Indicate that we are ready to process another commnad
_cmdProcessorReadyEvent.Set();

_sendCommandEvent.WaitOne();
lock (_sendCmdLock)
{
_lastCommandResult = new BaseResponse(false, false, "No Command");
RunCOMCommand(_currentCommand);
}

_resultAvailableEvent.Set();

} while (_processCommands);
}
catch (Exception ex)
{
_lastCommandResult.Success = false;
_lastCommandResult.Timeout = false;
_lastCommandResult.LastError = ex.Message;
}

}

我还没有尝试实现一个命令请求队列,因为调用代码期望所有内容都是同步的——也就是说,在我发送下一个命令之前,上一个命令必须已经完成。

其他背景

在远程系统上运行的软件是第 3 方产品,我无法访问它,它用于控制带有集成 XY 工作台的激光打标机。

我实际上正在使用遗留的 VB6 DLL 与激光通信,因为它具有用于格式化命令和处理响应的所有代码。此 VB6 DLL 使用 WinSock 控件进行通信。

最佳答案

我不确定为什么排队解决方案不起作用。

为什么不将每个请求以及带有结果的回调的详细信息放入队列中?您的应用程序会将这些请求排队,并且连接到您的第 3 方系统的模块可以轮流获取每个队列项、处理并返回结果。

我认为这是模块之间更清晰的关注点分离,而不是围绕请求分派(dispatch)等实现锁定。您的请求者在很大程度上忽略了序列化约束,第 3 方接口(interface)模块可以处理序列化、管理超时和其他错误等.

编辑:在 Java 世界中,我们有为消费者/发布者同步的 BlockingQueues,使这类事情变得非常容易。我不确定你在 C# 世界中是否有相同的东西。快速搜索表明没有,但是有源代码为这类事情四处漂浮(如果 C# 世界中的任何人都可以提供一些线索,我们将不胜感激)

关于c# - 如何序列化对异步资源的访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4885801/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com