有人能告诉我以下问题的一个好的工作解决方案吗?
我正在开发的应用程序需要通过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;
}
}我还没有尝试实现命令请求队列,因为调用代码希望所有内容都是同步的--也就是说,在发送下一个命令之前,前面的命令必须已经完成。
附加背景
在远程系统上运行的软件是第三方产品,我无法访问它,它用于控制激光打标机与集成XY表。
实际上,我正在使用遗留的VB6 DLL与激光通信,因为它拥有格式化命令和处理响应的所有代码。此VB6 DLL为通信使用WinSock控件。
发布于 2011-02-03 12:00:34
我不知道为什么排队的解决方案不起作用。
为什么不把每个请求,加上回调的细节和结果,放在一个队列上呢?您的应用程序将对这些请求进行排队,与第三方系统接口的模块可以依次接收每个队列项,处理并返回结果。
我认为这是模块间关注点的更清晰的分离,而不是围绕请求分发等实现锁定。您的请求者在很大程度上忽略了序列化约束,第三方接口模块可以处理序列化、管理超时和其他错误等等。
编辑:在Java世界中,我们有BlockingQueues,它是为消费者/发布者同步的,使这类事情变得非常容易。我不确定在C#世界里你是否也有同样的想法。快速搜索并不意味着会有这样的事情出现(如果C#世界中的任何人都能提供一些值得赞赏的信息)。
https://stackoverflow.com/questions/4885801
复制相似问题