首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何序列化对异步资源的访问?

如何序列化对异步资源的访问?
EN

Stack Overflow用户
提问于 2011-02-03 11:54:32
回答 1查看 1.5K关注 0票数 1

有人能告诉我以下问题的一个好的工作解决方案吗?

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

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

--我只需要一次只处理一个请求,也就是说,它需要序列化,否则,TCP通讯.就会发生不好的事情。

到目前为止尝试的解决方案

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

代码语言:javascript
复制
lock (_cmdLock)
{
SetPosition(position);
}

然而,我发现有时它不会释放锁,即使在远程系统和TCP通信上存在超时。另外,如果两个调用来自同一个线程(例如,用户双击了一个按钮),那么它就会通过锁--在再次读取关于锁定的信息之后,我知道同一个线程不会等待锁。

然后,我尝试使用AutoResetEvents一次只允许一个调用。但是如果没有锁定,它将无法处理多个线程。下面是我用来发送命令(从调用线程)和处理命令请求(运行在自己线程的后台)的代码

代码语言:javascript
复制
   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控件。

EN

回答 1

Stack Overflow用户

发布于 2011-02-03 12:00:34

我不知道为什么排队的解决方案不起作用。

为什么不把每个请求,加上回调的细节和结果,放在一个队列上呢?您的应用程序将对这些请求进行排队,与第三方系统接口的模块可以依次接收每个队列项,处理并返回结果。

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

编辑:在Java世界中,我们有BlockingQueues,它是为消费者/发布者同步的,使这类事情变得非常容易。我不确定在C#世界里你是否也有同样的想法。快速搜索并不意味着会有这样的事情出现(如果C#世界中的任何人都能提供一些值得赞赏的信息)。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4885801

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档