can*_*ice 1 c# multithreading tcp
谁能为我指出以下问题的有效解决方案?
我正在处理的应用程序需要通过TCP与另一系统上运行的软件进行通信。我发送到该系统的某些请求可能需要很长时间才能完成(最多15秒)。
在我的应用程序中,我有很多线程,包括主UI线程,可以访问与远程系统通信的服务。所有线程都只能访问该服务的一个实例。
我只需要一次处理一个请求,即它需要序列化,否则TCP通讯会发生不好的事情。
到目前为止尚未尝试的解决方案
最初,我尝试将lock()与静态对象一起使用以保护每个“命令”方法,如下所示:
lock (_cmdLock)
{
SetPosition(position);
}
Run Code Online (Sandbox Code Playgroud)
但是我发现,即使远程系统和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;
}
}
Run Code Online (Sandbox Code Playgroud)
我没有尝试实现命令请求队列,因为调用代码希望所有命令都是同步的,即,上一条命令必须在我发送下一条命令之前完成。
其他背景
在远程系统上运行的软件是第三方产品,我无法访问它,它用于控制带有集成XY工作台的激光打标机。
我实际上正在使用旧版VB6 DLL与激光器进行通信,因为它具有格式化命令和处理响应的所有代码。此VB6 DLL使用WinSock控件进行通讯。
我不确定为什么排队解决方案不起作用。
为什么不将每个请求以及带有结果的回调的详细信息放在队列中呢?您的应用程序会将这些请求放入队列,并且与您的第三方系统接口的模块可以依次获取每个队列项,进行处理并返回结果。
我认为这是模块之间关注的更清晰的分离,而不是在请求分发等周围实现锁定。您的请求者基本上忽略了序列化约束,并且第三方接口模块可以照顾序列化,管理超时和其他错误等。
编辑:在Java世界中,我们有BlockingQueues,它可以为使用者/发布者同步,并使这种事情变得很容易。我不确定在C#世界中是否也有相同的代码。快速搜索没有提示,但是这种事情有源代码(如果C#世界中的任何人都可以理解的话)
| 归档时间: |
|
| 查看次数: |
1020 次 |
| 最近记录: |