RH 属性的最佳实践

Best Practices for RH Properties

我有几个关于 RH 块最佳实践的问题。

首先,在 redhawksdr github 中是否有一个块可以作为所有 RH 块应该遵循的关于如何完成事情的示例?我在 redhawksdr gitub 站点中看到许多块,每个块似乎都以不同的方式执行日志记录和错误处理等操作。有些还没有删除默认生成的日志语句。

我们应该记录所有 属性 更改吗?使用 1.10 中新的 属性 回调,可以很容易地记录从旧到新的转换。如果是这样,我应该将它们记录到什么日志记录级别(例如 DEBUG 或 INFO)?其他人在做什么,为什么?

如果尝试设置 属性,但无法应用新设置,我们是否应该抛出异常并忽略新设置?我们应该记录错误或警告并确保没有异常从我们的组件传播出去吗?这些消息应该处于什么日志级别?我在 github 上看到一些块打印到 cerr 并且什么都不做。那些已经在实践中使用 RH 的人推荐使用什么方法?

一般来说,我们是否应该制作我们的区块,以便 属性 更改是完全发生或区块的内部状态根本不改变的事务。在 redhawksdr 的 github 上的一些块中,他们将尝试 属性 更改并打印错误,但此时状态并没有很好地定义。这在一般情况下是否可以接受,或者我们是否应该在这方面让一切都完全达到交易级别安全?

谈到组件开发的最佳实践时,REDHAWK 倾向于强调自由而不是一致性。不同的组件是根据不同的用例开发的,在 REDHAWK 中有许多不同的方法来解决问题。这解释了您在某些组件之间看到的一些差异。

有没有推荐的REDHAWK组件可以作为标准: 总的来说,GitHub 上发布的 REDHAWK 组件试图服务于两个目的。它们是用于处理的有用组件的集合。而且,它们是供其他人效仿的一组例子。

很难选出一个组件作为最好的例子,因为每个组件都是为不同的目的而编写的,并且采用了不同的方法。 HardLimit 组件可能是最简单的示例,因此它有助于理解开发组件的基础知识。 fastfilter 组件更复杂,它演示了一些更高级的概念,例如锁定和 属性 回调,以及覆盖配置以验证相互依赖的属性。

记录最佳实践: 简而言之,在开发 REDHAWK 组件时,在 system.out/system.error.

中使用 Logging 被认为是最佳实践

更广泛地说,日志记录在 REDHAWK 中可能是一个困难的主题。确实没有硬性规定。一般来说,发生的任何事情 "typically"(例如 - 在服务功能中接收数据包)都应该记录在 DEBUG 或 TRACE 中。 "normal" 操作之外的任何内容都应记录为 WARN。 ERROR 用于组件不应该出现的意外情况。在决定使用哪个级别时,请随时遵循 log4cxx 或 log4j 的准则。

一种常见的日志记录做法是在输入 Q 刷新时记录警告,这在许多组件上都可以看到。基本 class 实现在 TRACE 记录 属性 更改,因此组件开发人员不必在更高级别记录所有单独的 属性 更改。但是,如果他们选择这样做,他们可以选择在 属性 回调中记录重要属性(可能 DEBUG 或 INFO 是合适的级别)。

无效的 属性 配置: 在 REDHAWK 中,当组件配置不当时会抛出 Invalid Configuration。由开发人员决定他们的组件如何处理有关更新其内部状态的无效 属性 配置。这是组件开发人员做出的设计决策。如果您想回滚无效的 属性,属性 回调确实提供了一种 属性 验证机制。对于浮点数 属性 "myProp",代码可能如下所示:

void propChanged(const float *oldValue, const float *newValue)
{
    bool valid(true);
    // add custom logic to check the value here and set valid to false
    // For example, here is a check to ensure the property is postive:
    if (value<0)
        valid =false;
    if (!valid)
    {
        LOG_WARN(comp_i, "myProp received invalid value"<< *newValue);
        myProp=*oldValue; //reset property to original value 
        throw std::exception();
        //this causes base class to throw invalidConfiguration
    }

    //any additional logic for updating the component after the change goes here
}

在某些情况下,您可能不想将值重置为旧值,您可能希望将其设置为默认值(例如 - 将负数设置为 0)。这些都取决于开发者的判断力。在某些情况下,您可能希望将值四舍五入到特定的公差(例如四舍五入到最接近的 .001)并且根本不抛出无效配置。

线程安全 属性 变化: 属性 配置期间的线程并发非常重要,所有属性都应考虑。基础 classes 在配置和查询期间使用互斥锁 "propertySetAccess" 进行锁定,这提供了一种简单的方法来锁定并防止任何属性同时更改到其他处理。但是,这不是推荐的行为,因为有不同的方法来处理 属性 并发,并且在大多数情况下锁定所有 属性 配置更新是多余的。此外,值得注意的是,当以这种方式锁定时,锁在 属性 回调期间保持,因此回调不需要重新获取锁。

对于某些属性,如果值在处理数据包的过程中发生变化可能无关紧要。一个很好的例子是 HardLimit 中的 "upper_limit" 和 "lower_limit"。开发人员决定在处理过程中更改这些值并不重要,并且此组件没有 属性 并发。

对于一些属性,例如 fastfilter 中的 "fftSize",设计者决定他们永远不希望这个值在处理过程中改变。所以,他们有一个单独的互斥锁,"filterLock_",以防止这种情况发生。

另一种选择,而不是锁定,是制作 属性 的本地副本,然后在整个处理过程中使用该副本。当 属性 在循环中更改时,新值将应用于下一个服务函数。