同步原语

http://blog.csdn.net/h_cszc/article/details/7794089

ecos是多线程系统,并发执行造成了一些新问题的产生:多线程协同工作、对临界资源的竞争、线程间通信、线程间同步等等。其实,所有的多任务系统都会遇 到类似问题,计算机专家们总结了很多抽象模型来应对,方法手段很多,各有特色,每种操作系统可能只实现了某个子集。ecos内核的同步机制提供了许多同步 原语,包括:互斥、条件变量、信号量、信箱、事件标志和Spinlock等。
    
    抽象出来的同步原语操作主要包括:创建、删除、等待(阻塞/超时阻塞/非阻塞)、释放、设置、广播、查询数据、查询状态。
    
    虽然操作大同小异,但每种同步原语的含义和适用情况不同,下面详细介绍各种原语的使用方法和注意事项。
    
    ==========
    * 互斥体 *
    ==========
    互斥体用于实现线程对资源的安全共享。适用于线程间或线程与滞后中断服务程序DSR访问同一临界资源时的安全保护。
    考虑下面的例子:
    static volatile int counter = 0;
    void test(void)
    {
        ......
        counter++;
    }
    假设在某个时候counter的值为16,此时有两个同一优先级的线程A和B,它们都调用上面的test函数。线程A读取counter的值,并
将其值加1,此时,counter为17。线程B也做同样的操作,counter的值为18。但是如果线程A在读取counter的值为16后,在将其值
加1之前调度器调度运行线程B,此时,线程B读取的仍然是counter原来的值16,操作完成后counter变为17。这样,counter的值只增
加了1,而不是2,因此最后counter的值只是17,而不是18。这足以说明该应用程序的运行是不可靠的。
    使用互斥体就可以安全地操作counter全局变量:
    static volatile int counter = 0;
    static cyg_mutex_t lock;
    void test(void)
    {
        ......
        cyg_mutex_lock(&lock);
        counter++;
        cyg_mutex_unlock(&lock);
    }
    
    互斥体的使用可能会引起优先级倒置问题的出现。假设有三个不同优先级的线程A、B、C,优先级A>B>C。A和B由于等待事件而处于
阻塞状态,C得以运行。线程C在进入临界区时锁定了一个互斥体。当线程A、B被唤醒时,线程A要等待同一个互斥体,但它在线程C离开临界区并释放互斥体之
前不得不等待。与此同时,线程B却可以毫无问题地正常运行。由于线程C比线程B优先级低,它在B被阻塞前将没有机会运行。这样线程A就不能运行。其结果就
是高优先级的线程A由于优先级比它低的线程B的原因而无法运行,这就发生了优先级倒置。
    
    解决优先级倒置问题普遍使用的技术是:优先级置顶协议(Priority Ceiling Protocol)和优先级继承协议(Priority Inheritance Protocol)。
    优先级置顶意味着占有互斥体的线程在运行时的优先级比任何其他可以获取该互斥体的线程的优先级都要高。ecos组件包通常无法知道系统中各种线程的详细信息,因此无法对组件包内部使用的互斥体设置合适的置顶优先级。设置高了会影响调度操作。
    优先级继承将占有互斥体的线程优先级提升到所有正在等待该互斥体的线程优先级的最高值。当一个线程等待正被另一优先级较低的线程占有的互斥体时,
拥有该互斥体的线程优先级被提升到正在等待该互斥体的线程优先级,优先级继承比优先级置顶效率高,不过增加了同步调用开销,而且实现起来比优先级置顶复
杂。
    
    初始化          cyg_mutex_init
    删除            cyg_mutex_destroy
    锁定            cyg_mutex_lock
    尝试锁定        cyg_mutex_trylock
    解锁            cyg_mutex_unlock
    释放            cyg_mutex_release
    设置置顶优先级  cyg_mutex_set_ceiling
    设置协议        cyg_mutex_set_protocol
    
    ============
    * 条件变量 *
    ============
    条件变量是允许线程同时给多个线程发信号的一个同步机制。当线程等待一个条件变量时,它在进入等待状态之前将释放互斥体,在被唤醒后又重新拥有互斥体。这种操作是原子操作。
    
    举例说明见例1。
    
    初始化          cyg_cond_init
    删除            cyg_cond_destroy
    等待            cyg_cond_wait
    唤醒            cyg_cond_signal
    广播            cyg_cond_broadcast
    带超时等待      cyg_cond_timed_wait
    
    ==========
    * 信号量 *
    ==========
    信号量是一个允许线程等待直到事件发生的同步原语。每个信号量都有一个整数计数器,如果计数器为0,那么等待该信号量的线程将被阻塞。如果计数器
大于0,那么等待的线程将消耗一个事件,即计数器减1。唤醒信号量将对计数器加1。即使事件连续快速发生多次,信号量也不会丢失信息。
    信号量的另一个用途是对资源的管理。计数器的值与当前可用资源的数目相对应。实际上,条件变量更适合于这种操作。
    
    初始化          cyg_semaphore_init
    删除            cyg_semaphore_destroy
    等待            cyg_semaphore_wait
    带超时等待      cyg_semaphore_timed_wait
    非阻塞等待      cyg_semaphore_trywait
    唤醒            cyg_semaphore_post
    获取信息        cyg_semaphore_peek
    
    ========
    * 信箱 *
    ========
    信箱是一个类似于信号量的同步原语,还可以在事件发生时传递一些数据。有些系统称之为消息队列。被称为消息的数据通常是数据结构的指针。信箱只具有有限的容量,缺省配置为10个槽位,有可能溢出。因此,信箱通常不能被DSR用来唤醒线程。
    
    创建            cyg_mbox_create
    删除            cyg_mbox_delete
    获得消息        cyg_mbox_get
    带超时获得消息  cyg_mbox_timed_get
    非阻塞获得消息  cyg_mbox_tryget
    非删除获得消息  cyg_mbox_peek_item
    发送消息        cyg_mbox_put
    带超时发送消息  cyg_mbox_timed_put
    非阻塞发送消息  cyg_mbox_tryput
    读取消息数      cyg_mbox_peek
    判断是否有消息  cyg_mbox_waiting_to_get
    发新消息前判断  cyg_mbox_waiting_to_put
    
    ============
    * 事件标志 *
    ============
    事件标志允许线程等待一个或几个不同类型的事件发生。还可以用于等待某些事件组合的发生。事件标志不存在溢出问题。

    事件标志可以指定函数调用者阻塞(1)直到所有指定事件发生为止;(2)直到至少一个指定事件发生为止;(3)直到所有指定事件发生为止并清除事件标志;(2)直到至少一个指定事件发生为止并清除事件标志。

    
    初始化              cyg_flag_init
    删除                cyg_flag_destroy
    设置标志位          cyg_flag_setbits
    清除标志位          cyg_flag_maskbits
    等待事件发生        cyg_flag_wait
    超时等待事件        cyg_flag_timed_wait
    探查事件是否发生    cyg_flag_poll
    返回事件标志当前值  cyg_flag_peek
    报告是否有线程等待  cyg_flag_waiting
    
    ============
    * Spinlock *
    ============
    Spinlock是为SMP系统中的应用线程提供的一个同步原语。Spinlock运行级别要低于其他同步原语(如互斥体)。特别在对中断进行处
理以及线程需要共享硬件资源的情况下需要使用Spinlock。在SMP系统中,内核自身的实现也需要使用Spinlock。
    必须强调的是,对Spinlock的拥有时间必须很短,一般为几十条指令。在单处理器系统中,不应该使用Spinlock。
    
    初始化          cyg_spinlock_init
    删除            cyg_spinlock_destroy
    声称            cyg_spinlock_spin
    释放            cyg_spinlock_clear
    非阻塞声称      cyg_spinlock_try
    检查是否有等待  cyg_spinlock_test
    安全声称        cyg_spinlock_spin_intsave
    安全释放        cyg_spinlock_clear_intsave

时间: 2025-01-13 14:41:30

同步原语的相关文章

同步原语之信号量

一.semaphore信号量分析 首先,说明信号量的作用,信号量的作用类似于自旋锁(其实,同步原语均有相似之处),相似之处在于,都有临界区,各进程需互斥访问,linux中提供了两种信号量的实现,有内核态的和用户态的,这里只介绍内核态的 相关数据结构 1 struct semaphore { 2 spinlock_t lock; 3 unsigned int count; 4 struct list_head wait_list; 5 }; 1 struct mutex { 2 /* 1: unl

C#并行编程-线程同步原语(Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait,Monitor,volatile)

菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要访问共享的数据和资源的时候,您必须添加显示的同步,或者使用原子操作或锁. 之前的.NET Framework提供了昂贵的锁机制以及遗留的多线程模型,新的数据结构允许细粒度的并发和并行化,并且降低一定必要的开销,这些数据结

C#并行编程-线程同步原语

原文:C#并行编程-线程同步原语 菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 背景 有时候必须访问变量.实例.方法.属性或者结构体,而这些并没有准备好用于并发访问,或者有时候需要执行部分代码,而这些代码必须单独运行,这是不得不通过将任务分解的方式让它们独立运行. 当任务和线程要访问共享的数据和资源的时候,您必须添加显示的同步,或者使用原子操作或锁. 之前的.NET Framework提供了昂贵的锁机制以及遗留的多线程模型,新的数据结构允许细粒度的并发和并行化,

.NET同步原语Barrier简介

Barrier(屏障)是一种自定义的同步原语(synchronization primitive),它解决了多个线程(参与者)在多个阶段之间的并发和协调问题. 1)多个参与者执行相同的几个阶段的操作 2)在每一个阶段内,多个参与者并发执行 3)一个屏障点代表一个阶段的结束 4)一个参与者运行至屏障点时被阻塞,需要等待其他参与者都到达屏障点 5)所有参与者都到达了屏障点,才可以进入下一个阶段 创建Barrier时,需要指定参与者数量.它允许动态的添加或者删除参与者. Barrier适合多个线程执行

python多线程编程—同步原语入门(锁Lock、信号量(Bounded)Semaphore)

摘录python核心编程 一般的,多线程代码中,总有一些特定的函数或者代码块不希望(或不应该)被多个线程同时执行(比如两个线程运行的顺序发生变化,就可能造成代码的执行轨迹或者行为不相同,或者产生不一致的数据),比如修改数据库.更新文件或其他会产生竞态条件的类似情况.此时就需要同步了. 同步:任意数量的线程可以访问临界区的代码,但在给定的时刻又只有一个线程可以通过时. 这里介绍两个基本的同步类型原语:锁/互斥.信号量 锁 锁有两种状态:锁定和未锁定.与之对应的是两个函数:获得锁和释放锁. 当多线程

Linux内核同步原语之原子操作

避免对同一数据的并发访问(通常由中断.对称多处理器.内核抢占等引起)称为同步. --题记 内核源码:Linux-2.6.38.8.tar.bz2 目标平台:ARM体系结构 原子操作确保对同一数据的"读取-修改-写入"操作在它的执行期间不会被打断,要么全部执行完成,要么根本不会执行.例如在ARM上对全局变量的++运算至少要经历以下三步: [cpp] view plain copy print? ldr r3, [r3, #0] add r2, r3, #1 str r2, [r3, #0

.NET线程同步原语

[独占] 用户模式 Interlock原子锁,Spinlock自旋锁 内核模式 Mutex互斥锁(那个线程获取,那个线程释放:可以跨进程) 混合模式 Monter [信号量] 一批 内核模式 semaphore(可以跨进程) 混合模式 SemaphoreSlim(不可跨进程) [事件通知] 一个事件 内核模式 ManualResetEvent, AutoResetEvent(可以跨进程) 混合模式 ManualResetEventSlim, AutoResetEventSlim(不可跨进程) [

Java并发原语——线程、互斥与同步

本文将介绍: Java线程基本操作(创建.等待等) Java线程同步原语(同步.互斥) 如果你对以上话题已了如指掌,请止步. Java线程基本操作 Java的线程API以java.lang.Thread类提供,线程的基本操作被封装为为Thread类的方法,其中常用的方法是:   方法 说明 void start() 启动线程 void join() 等待线程结束 创建(启动)线程 Java中,创建线程的过程分为两步: 创建可执行(Runnable)的线程对象: 调用它的start()方法: 可执

11.6 线程同步

11.6.1 互斥Example11.6.2 避免死锁Example11.6.3 pthread_mutex_timedlock 函数Example11.6.4Reader-Writer LocksExample11.6.5 带有超时功能的读写锁11.6.6 条件变量Example11.6.7 自旋锁11.6.8 BarriersExample 当多个线程控制流需要共享内存的时候,我们需要确保每一个线程所看到的数据是一致的.如果一个线程使用别的线程不会读取或者修改的数据,那么一致性问题并不会出现