在多线程环境中使用newlib库

ZDNet软件频道 时间:2003-06-16 作者:ZDNet China |  我要评论()
本文关键词:embedded
Newlib提供了一个复杂的函数集,使用它们能够让你集中精力在真正的工作上。现在,让我们看一下newlib库中的文件流I/O函数,并且讨论在一个多线程实时操作系统环境中如何安全使用newlib苦。
本文译自Builder.com,未经许可请勿转载 上一次,我向你介绍了newlib,一个面向嵌入式系统的开源C语言程序库。Newlib提供了一个复杂的函数集,使用它们能够让你集中精力在真正的工作上。

我还提供了当使用newlib时需要实现的系统调用例程列表。现在,让我们看一下newlib库中的文件流I/O函数,并且讨论在一个多线程实时操作系统环境中如何安全使用newlib苦。
文件和I/O流支持

文件流I/O函数,例如fopen(), fread(), fwrite(), fprintf(), 和fclose(), 在newlib库中很容易被混淆。这里有一个固有的文件系统吗?没有。在你所提供的基于句柄系统调用例程_open(), _read(), _write(), 和 _close()的顶部,这些newlib函数只提供了缓冲区的流I/O层。

这里的基本原理是你能够像在UNIX/POSIX中对待文件那样处理I/O设备。你的系统调用例程能够将文件I/O请求定向到你想要的地方:串口,LCD显示屏,块存储设备,文件系统驱动器等等。

如果你有多个设备,当你通过_open().打开一个设备时需要返回一个唯一的句柄。然后函数_read(), _write(), 和 _close()通过这个句柄参数决定将一个请求定向到哪一个设备上。

不要忽视这一工具,不要低估这种机制的力量。

在多线程环境中使用newlib

C的标准库是天生没有重进入点的。如果没有顾虑的这一点,它将导致在多线程实时操作系统环境中的使用不安全。这是因为某些函数需要静态数据来保持调用的状态信息,而其他函数依赖errno静态变量来报告错误代码。如果多线程中的函数调用修改了相同的静态数据,将发生致命的混淆。

幸运的是,newlib库代码已经涵盖了这一点。没有在简单的存储位置存储它的静态变量,newlib库定义了 _reent结构封装了库中需要的所有静态变量。一个单一的指针(_impure_ptr)指向了_reent数据块。newlib库中的所有函数都使用了_impure_ptr 指向的_reent数据块中的“静态“数据。

这种机制的背后是这样一种思想,在一个多线程环境中,每个任务必须由它自己的_reent数据块。进一步,无论实时操作系统什么时候执行一个任务切换,你必须为这个新激活的任务改变指向的_reent数据块的_impure_ptr指针。

如果在一个多线程环境中运行newlib库,要注意两点:

  1. 为每一个任务分配一个_reent结构
  2. 在实时操作系统上下文切换中,为这个新激活的任务改变指向的_reent数据块的_impure_ptr指针

如果在你的实时操作系统里有合适的系统调用,你通常很容易的实现这些(更容易的是你有实时操作系统的源代码)。

系统默认地为单线程环境保留一个的_impure_ptr指针指向的_reent结构实例。所以,如果你不运行多线程应用,你不用考虑这些问题。

当你写嵌入式应用的代码时,你也不需要明白这种机制。例如,可以按照往常那样修改标准C的errno变量,如下所示:

errno = 0;

但是在这种情形的背后,errno被一个宏定义实现成以下代码,所以每个人物犹他自己的私有errno变量。

_impure_ptr->errno = 0

保护newlib的堆管理器

在多线程环境中,使用malloc() 和free()函数可以保护对newlib所管理的系统堆的访问。不要让两个以上的任务同时操纵堆。

在强调一下,newlib使在访问对管理结构前后调用_malloc_lock() 和 _malloc_unlock()系统例程变得简单,本着使用实时操作系统的互斥机制保证在同一时间只有同一任务访问堆的原则,来实现_malloc_lock() 和 _malloc_unlock()就可以了。

不要跳过这一步。即使嵌入式应用中没有明确的调用malloc(),newlib库内部有时也会自己使用malloc()。



责任编辑:炒饭

欢迎评论或投稿


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134