作者:Steve Leibson, 赛灵思战略营销与业务规划总监
在我前面的一篇博客(查看“Adam Taylor玩转MicroZed系列40:MicroZed操作系统第二部分”)中,大家已经见识了不同类型的实时操作系统。我认为我们应该了解一下操作系统执行的进程之间是如何进行通信的,它们是怎样共享可用的硬件资源和潜在的陷阱(计算机异常的一个类别)。
当两个或者更多的进程想要共享同一个资源——以Zynq SoC 的XADC组件为例——很多进程很可能会在同一时间要求使用这个资源。资源的访问使用需要被控制来阻止出现争夺资源的现象,这是操作系统最重要的职责之一。如果不能正确有效的实现资源的管理,“死锁”(deadlock)或者“饥饿”(starvation)现象可能会发生。
下面给出的是“死锁”和“饥饿”的定义:
死锁——当一个进程占有一个资源,直到这个进程结束才会释放这个资源,但是因为它需要一个被另一个的进程占用的资源导致它不能被执行完毕。如果第二个进程需要调用第一个进程占用的资源,那么系统就永远保持在死锁状态。死锁现象是RTOS(实时操作系统)自身的一个比较糟糕的情况。
饥饿——进程不能够运行,因为这个进程所需的资源总是被分配给另一个进程,这个进程就会因为缺乏资源而被“饿死”,俗话说“巧妇难为无米之炊。”
正如你能够想象到的,历年来很多文章介绍和讨论了关于死锁和饥饿现象这个主题,涌现出了很多可行性的解决方案。例如:Dekker算法,这个算法是首先被认为是解决互斥现象的正确方案。它是一个共享内存的机制,不需要特定的“测试与设置”指令(但是仅限于管理两个竞争的进程),这都要归功于荷兰数学家Theodorus Dekker。处理死锁现象最普遍的方法是利用semaphores(信号量),主要有两种形式:二进制信号量和计数器信号量。二进制信号量用于控制对一个资源的访问,例如一个硬件资源。计数器信号量用于控制对一堆相同的可以内部互换的资源的访问,例如内存的缓冲区。
通常情况下每个资源都会分配一个二进制的信号量,调用这个资源的进程将会等待,直到这个资源变成可利用的,进程才会执行,一旦这个进程执行完毕,它将会释放这个资源。二进制信号量通常使用WAIT和SIGNAL操作。进程会根据一个信号量执行WAIT操作,当这个资源处于空闲状态(可能是立即空闲或者不是) ,操作系统会把资源的控制权交给进程。
当进程执行完毕,会产生SIGNAL完成信号并且释放资源。然而,当进程根据信号量等待时,如果资源是被占用的,操作系统会暂停进程直到资源处于空闲状态。这个执行WAIT操作的进程可能不得不一直等待,直到占用这个资源的正在执行的进程结束,或者这个等待可能会更长,如果这个资源已经被更高优先级的进程请求调用。
介绍进程优先级的概念会引出优先级反转这个问题。存在一个更加灵活的二进制信号量的类被称作“mutex’s”(单词mutex是“mutual exclusion”的缩写),这些类经常会被现代操作系统使用,用来防止优先级反转。
计数器信号量的工作方式与二进制信号量的工作方式相,当不止一个资源师是可利用的时候它们会被调用,例如数据的存储。随着每个资源被分配给请求的进程,计数器的值会减少来反映出剩余的空闲资源的数量。当信号量计数器的值变为零,就不会存在可利用的资源。当计数器的值变为零以后任何请求一个或者更多资源的进程都将会被暂停,直到所需数量的资源被释放。
进程之间需要经常的进行通信,又很多的方法来实现这个操作。最简单的方法是使用数据存储,数据存储是用上面描述的信号量进行管理的,更复杂的通信方法包括消息队列。
当使用消息队列时,一个进程想要发送信息给另一个进程要发布一个消息到这个队列里面。当一个进程想要从队列里接收消息,他就会依赖于这个队列。因此消息队列的工作方式像FIFO。然而在µC/OS-III操作系统会配置消息队列以LIFO方式工作。消息队列和它们所属的组织可能很复杂,想要深入探讨这个话题可能需要写更多的博客。幸运的是通过借助操作系统中预先写入的程序,这些编程工具更加的容易使用,不用再去从头创建。
已经解释了一点儿关于资源共享和进程间通信的知识,我的下一篇博客将会介绍µC/OS-III OS的一个演示例子,并且在MicroZed上运行起来。
原文链接:
http://forums.xilinx.com/t5/Xcell-Daily-Blog/Adam-Taylor-s-MicroZed-Chro...
© Copyright 2014 Xilinx Inc
如需转载,请注明出处