我有一个视差螺旋桨,这是一个8核微控制器,时钟频率为80MHz(即它比Arduino好得多,但并不惊人)。
我需要在整个代码中访问一些变量 - 俯仰和滚动角度等等(所有浮点数)。我的目的是将它们声明为 extern volatiles——只在类内设置的全局变量,并且只在其他地方读取(易失性在那里,因为它是多核的)(extern 因为类在一个单独的文件中)。
这是不好的做法吗?我试图避免使用函数调用它们,因为这只会减慢速度 - 所有变量都存储在主 ram 中,因此它们如何放置在那里并不重要。有没有更好的方法可以做到这一点?
假设使用函数调用它们更好,这将如何完成?
volatile
保证编译器不会"优化对变量的访问"(经典示例是:
bool b = false;
while(!b) /* do nothing */;
编译器转向:
bool b = false;
bool tmp = !b; // tmp is really a processor register.
while(tmp) /* do nothing */;
由于循环中的任何内容都没有改变b
,因此编译器这样做是一个有效的优化。
volatile bool b;
将保证每次在代码中"使用"b
时,编译器都会读取/写入实际变量,而不是一些"临时副本"。
但是,volatile
不保证:
- 数据是
原子更新的——换句话说,如果你存储了一些东西,一半新数据可能会被存储,而另一半是旧值,导致各种"有趣的"结果[例如
float
中的随机值]。
其他 CPU 的缓存知道该值已更改 - 换句话说,一个 CPU 读取的值可能已在另一个 CPU 上更新 - 比如
b
上面的代码 - 鄙视volatile
,CPU 很可能没有导致另一个 CPU 的缓存刷新。
您需要注意缓存和原子更新,以确保您不会因其中任何一个未正确完成而导致"有趣"的错误。无论您是否使用全局变量或以其他方式在处理器之间共享数据,这当然都适用 - 您可以依赖它的唯一情况是通过操作系统或运行时环境拥有适当的接口,这为这些事情提供了保证。
对于主题问题:不,在微控制器中使用全局变量不一定是坏事。螺旋桨是否"低功率"是有争议的,但如果我没记错的话,它既没有浮点数,也没有功能来进行多字原子访问。它中的任何内核都有 1/8 的主内存访问周期,无论它是否愿意。
您描述了将态度存储在一组全局变量中。如果每个单词都可以独立更新并在一个原子操作中写入(我相信螺旋桨具有 32 位 RAM 和处理器),您可以忽略同步,但如果需要关联测量值,您想使用某种屏障或锁。螺旋桨被设计为通过可预测的时间在没有锁的情况下运行,但这基本上仅适用于周期计数装配程序员;它根本无法帮助您C++。
螺旋桨确实有硬件锁,通过一组毫无意义和有限的测试和设置基元来实现。如果您设法理解它们的 Spin 文档,则可以使用它们(因为数据表和 GCC 文档都没有涵盖它们的语义)。
至于这个控制器比Arduino"好很多"?我不会说这是理所当然的。它只有原始定时器和视频生成外围设备(其他任何事情都在软件中完成),与AVR的典型一两个周期相比,处理器每条指令需要四个周期,而且您可以轻松地获得基于Cortex M4F的微控制器,它确实具有浮点数。
该问题继承自多线程应用程序,即两个或多个线程可以访问(读取或写入)一个并行变量。在这种情况下,同步是最重要的方面之一。使用哪种技术(锁定、原子操作、信号量等)都是一样的,您可以避免变量的不一致(即在读取操作期间,另一个线程写入变量)。
因此,如果使用外部全局变量,则所有外部模块都可以直接访问此变量而无需同步。当然,实现指定模块的开发人员可以使用原子操作(或其他解决方案),但这取决于他或她的注意力,同步的责任由访问全局变量的所有外部模块承担,这是一种糟糕的方法,(如果可能的话)你必须避免。
作为大多数多线程系统的解决方案,所有可以直接访问变量的方法都必须在同一模块中实现。此解决方案的优点:
-
该方法可以使用通用同步解决方案,因此解决了变量的并行和同步访问问题。
-
通常,一个模块由一个开发人员实现,因此同步错误也减少了。
-
其他模块(和其他开发人员)将获得一个指定良好且同步的接口来访问公共资源(全局变量)。
因此,外部模块只能通过接口方法访问这些全局变量。当然,在这种情况下会出现一些微不足道的调用开销,但如果你想避免它并使你的代码更有效率,你可以将这些接口方法声明为内联方法。
螺旋桨上的gcc或C冲击充其量是一种黑客,多核功能和东西被扔掉以使C可用。 因此,虽然说 C 标准这个或那个或关于全局的宗教辩论是一回事,但随后在该平台上实现 C 可能真正符合也可能不符合任何上述标准。
我同意另一个人的观点,如果按设计使用螺旋桨,则具有一些有趣的功能,但是arduino要干净得多,几乎任何东西都是。 如果你真的想要硬件多线程与XMOS一起使用,它有自己的C实现功能,非常酷的硬件在风格/设计上,但不像功耗那样酷。 螺旋桨是一个整洁的玩具,如果你扔掉 C 并按设计使用它,一旦你使用 C,你就会瘫痪它并把它变成一个非常弱的微控制器,几乎所有其他竞争对手在这一点上都更好。 当我终于买了一个并看向窗帘后面时,我感到非常失望。
除非存在实现问题,否则可以使用全局变量并在这些全局变量上使用易失性来获取共享该全局变量的代码。 可能会在某些人的嘴里留下不好的味道,但根据规格,它应该有效。