实现通信超时

时间:2010-09-29 02:08:37

标签: c++ windows communication

我正在实现一个通过USB设备与电机控制器通信的类。我有一切工作,除了指示通过comm链接获取的参数是否“新鲜”的方式。到目前为止我所拥有的:

class MyCommClass
{
public:
  bool getSpeed( double *speed );

private:
  void rxThread();

  struct MsgBase 
  { /* .. */ };

  struct Msg1 : public MsgBase
  { /* .. */ };

  struct Msg2 : public MsgBase
  { /* .. */ };

  /* .. */

  struct MsgN : public MsgBase
  { /* .. */ };

  Msg1 msg1;
  Msg2 msg2;
  /* .. */
  MsgN msgn;

  std::map< unsigned long id, MsgBase *msg > messages;
};

rxThead()是一个无限循环,在一个单独的线程中运行,检查USB设备是否有可用消息。每封邮件都有一个唯一标识符rxThread()用于将其粘贴到正确的msgx对象中。我需要的是当用户调用getSpeed()函数时,它需要能够判断当前速度值是“新鲜”还是“陈旧”,即包含速度值的msgx对象是否为在指定的超时期限内更新。因此,每个消息对象都需要实现自己的超时(因为它们因每条消息而异)。

所有消息都由电机控制器定期发送,但也有一些消息在内容发生变化时立即发送(但如果内容不变,它们也会定期发送)。这意味着接收超过标称速率的消息是可以的,但它应该在最大超时时间内至少出现一次。

USB设备提供时间戳和消息,因此我可以访问该信息。时间戳不反映当前时间,它是具有微秒分辨率的unsigned long数字,设备每次收到消息时都会更新。我怀疑设备刚从我调用其初始化函数时开始从0开始递增。我能想到实现这一点的几种不同方式是:

  • 每个消息对象都会启动一个在超时期间无限运行(WaitForSingleObject)的线程。超时后,它会检查计数器变量(在等待之前缓存)是否已递增。如果没有,它会设置一个标记消息为过时的标志。每次rxThread()更新该消息对象时,计数器都会递增。

  • rxThread()除填充消息外,还会遍历消息列表并检查每个消息的上次更新时间戳。如果时间戳超过超时,则将消息标记为失效。此方法可能存在所需处理量的问题。它可能不会成为大多数机器的问题,但这个代码需要在速度慢的“工业计算机”上运行。

我非常感谢您对如何实施这一点的想法和建议。我对除了我提到的两个以外的想法持开放态度。我正在使用Visual Studio 2005,因为USB设备驱动程序仅限Windows,因此跨平台可移植性不是一个大问题。目前我正在监控大约8条消息,但如果解决方案足够轻,我可以添加几个(可能是另外8个),而不会遇到处理功能限制,这将是很好的。

提前致谢, 与Ashish。

2 个答案:

答案 0 :(得分:1)

如何在邮件中存储时间戳,并getSpeed()检查时间戳?

答案 1 :(得分:1)

如果您在消息变得陈旧时不需要“立即”做某事,我认为如果您将计算机的时间和设备的时间戳存储在每条消息中,您可以跳过使用计时器:

#include <ctime>
#include <climits>

class TimeStamps {
public:
  std::time_t sys_time() const;   // in seconds
  unsigned long dev_time() const; // in ms
  /* .. */
};

class MyCommClass {
  /* .. */
private:
  struct MsgBase {
    TimeStamps time;
    /* .. */
  };

  TimeStamps most_recent_time;

  bool msg_stale(MsgBase const& msg, unsigned long ms_timeout) const {
    if (most_recent_time.sys_time() - msg.time.sys_time() > ULONG_MAX/1000)
      return true; // device timestamps have wrapped around
    // Note the subtraction may "wrap".
    return most_recent_time.dev_time() - msg.time.dev_time() >= ms_timeout;
  }
  /* .. */
};

当然,如果您愿意,TimeStamps可以是MyCommClass中的另一个嵌套类。

最后,每次收到消息时,rxThread()都应该设置相应的消息的TimeStamps对象和most_recent_time成员。如果在收到任何其他类型的最后一条消息后它变得陈旧,所有这些都不会检测到过时的消息,但是你在问题中的第二个可能的解决方案会有同样的问题,所以也许这无关紧要。如果它确实重要,如果msg_stale()也比较当前时间,这样的事情仍然有效。