您的位置:  首页 > 技术杂谈 > 正文

任务间同步 | 信号量、互斥量和事件集

2022-02-28 16:00 https://my.oschina.net/u/5443273/blog/5465717 中国移动OneOS 次阅读 条评论

本文分享自中移OneOS微信公众号《任务间同步》,主要介绍互斥量、信号量、事件集在任务间同步过程中起到的作用,并通过对其概念、控制块结构和接口设计的讲解帮助开发者更好的理解其在操作系统中的应用。

多个任务操作同一块代码区域,这块代码就称为临界区,如果任何时刻最多只允许一个任务去使用临界区,那么多个任务就需要互斥的访问。当一个任务占用此资源时,其它需要该资源的任务必须等待,直到占用者释放资源。

另外一种使用场景是任务间同步,是指多个关联任务需要按预定的次序运行,如果没有同步,那任务之间将是无序、不符合预期的。

互斥量

互斥量有解锁加锁两种状态,初始化时互斥量处于解锁状态,当有任务获取该互斥量后,处于加锁状态,此时其他任务没有权限再获取该互斥量,直到当前任务释放。同时,互斥量具有递归特性,持有该互斥量的任务也能够再次获取而不被挂起。

在操作系统中,使用优先级继承算法解决优先级翻转问题。优先级翻转是指当一个高优先级任务H通过同步机制访问同步资源时,该资源已被一低优先级任务L占有,而系统中还有中优先级的任务M在执行,造成L得不到调度,高优先级任务H就一直被阻塞,结果M先于H执行,优先级发生了翻转,实时性难以得到保证。优先级继承算法实现如下,高优先级任务H在等待低优先级的任务L占用的同步资源时,由操作系统把L的优先级提高到H的优先级,从而让L以H的优先级参与调度,尽快执行并释放资源,然后L的优先级调整到继承前的值,此时H可获得竞争资源而继续执行,如下图。

<优先级继承示意图>

互斥量控制块是操作系统用于管理互斥量的一个数据结构,由结构体os_mutex_t表示。控制块结构的详细定义请见以下代码:

struct os_mutex 
{  
    os_ipc_object_t  parent;            /* 继承自os_ipc_object 类*/ 
    os_uint16_t      value;               /* 互斥量的值*/ 
    os_uint8_t       original_priority;  /* 持有任务的原始优先级*/ 
    os_uint8_t       nested;              /* 持有任务的持有次数*/ 
    os_task_t       *owner;             /* 当前拥有互斥量的任务*/ 
       };

互斥量接口设计如下:

(1)创建互斥量

(2)销毁互斥量

(3)获取互斥量

(4)释放互斥量

信号量

信号量是一种轻型的用于解决任务间同步问题的内核对象,任务可以获取或释放它,从而达到同步或互斥的目的。

信号量初始化为大于0的整数,表示资源的数量,当一个任务申请到一个资源后将该整数减1,当该整数值为0时,所有试图申请的任务都将处于阻塞状态。在信号量上定义两种操作:wait(获取)和post(释放)。当一个任务调用wait操作时,它要么得到资源然后将信号量减1,要么一直等下去。当有其他任务释放资源,调用post在信号量上执行加1操作,阻塞等待的任务可以得到执行。

信号量控制块结构的详细定义如下:


struct os_semaphore 
{ 
    os_ipc_object_t     parent; /* 继承自os_ipc_object 类*/  
    os_uint16_t         count;   /* 信号量的值*/ 
}; 

信号量接口设计如下:

(1)创建信号量

(2)销毁信号量

(3)获取信号量

(4)无等待获取信号量

(5)释放信号量

事件集

事件集可以实现一对多,多对多的同步。任务可以设计成为被一个事件组合唤醒,事件组合可以包含一个或者多个事件的“与”或“或”的关系。

系统使用一个32位无符号整型变量来表示这种事件集的关系,变量的每一位代表一个事件,也就是系统最多支持32个事件。通过“与”或“或”将一个或多个事件关联起来,形成事件组合。通过“或”组合的事件集中的任何一个事件都可以唤醒任务;通过“与”组合的事件集需要所有事件都发生后才可以唤醒任务。

因为32位无符号整型的一个位记录一种事件,无记录次数功能,如果任务还未处理该事件时又发生同一个事件,其效果等同于只发送一次。

事件集控制块结构的详细定义如下:


struct os_event 
{ 
    os_ipc_object_t  parent;  /* 继承自os_ipc_object 类*/ 
    os_uint32_t      set;       /* 事件集合,每一bit 表示1 个事件,*/
                                  /* bit 位的值可以标记某事件是否发生 */
}; 

事件集接口设计如下:

(1)动态创建事件集

(2)销毁事件集

(3)发送事件

(4)接收事件集

展开阅读全文
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接