临界区是仅容许一个线程访问的共享资源。它能够是一个具体的硬件设备,也能够是一个变量、一个缓冲区。多个线程必须互斥的对他们进行访问html
禁止调度算法
/* 调度器商锁,上锁后再也不切换到其余线程,仅响应中断 */ rt_enter_critical(); /* 临界操做 */ rt_exit_critical();
关闭中断:由于全部的线程的调度都是创建在中断的基础上的,因此当关闭中断后系统将不能再进行调度,线程自身也天然不会被其余线程抢占了编程
rt_base_t level; /* 关闭中断 */ level = rt_hw_interrupt_disable(); /* 临界操做 */ rt_hw_interrupt_enable(level);
信号量、互斥量缓存
嵌入式系统运行的代码主要包括线程和ISR,在它们的运行过程当中,它们的运行步骤有时须要同步(按照预约的前后次序运行),有时访问的资源须要互斥(一个时刻只容许一个线程访问资源),有时也须要比本次交换数据。这些机制成为进程间通讯IPC。RT-Thread中的IPC机制包括信号量、互斥量、事件、邮箱、消息队列。经过IPC,能够协调多个线程(包括ISR)默契的工做。信号量是一种轻型的用于解决线程间同步问题的内核对象,线程能够获取或释放它,从而达到同步或互斥的目的。每一个信号量对象都有一个信号量值和一个线程等待队列。信号量的值对应信号量对象的实例数目(资源数目),若是信号量值N,则表示有N个信号量实例(资源)可被使用。当值为0时,再请求该信号量的的线程,就会被挂起在该信号量的等待队列上。数据结构
struct rt_semaphore { struct rt_ipc_object parent; /* IPC对象继承而来 */ rt_uint16_t value; /* 信号量的值 */ } 静态信号量:struct rt_semaphore static_sem 动态信号量:rt_sem_t dynamic_sem typedef struct rt_semaphore *rt_sem_t;
静态信号量: rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag) rt_err_t rt_sem_detach(rt_sem_t sem) //将不用的静态信号量从系统中脱离
判断一下返回值是否是RT_NULL 动态信号量: rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag) //等待队列中的线程,当有资源的时候: RT_IPC_FLAG_FIFO先来先服务,前后顺序排列 RT_IPC_FLAG_PRIO按照线程优先级排列 rt_err_t rt_sem_delete(rt_sem_t sem)//释放系统资源
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time) //RT_WAITING_FOREVER = -1, 以系统滴答时钟为单位。即100HZ,等待10ms的倍数。若是超时则返回-RT_ETIMEOUT.切忌该函数不可在中断中调用,由于它会致使线程被挂起。只能在线程调用 rt_err_t rt_sem_trytake(rt_sem_t sem) //时间参数为0,一秒钟都不等待
rt_err_t rt_sem_release(rt_sem_t sem) // 既能够在线程,也能够在中断中调用。由于它不会致使线程被挂起
两个线程,一个生产者线程和一个消费者线程,两个线程共享一个初始为空、固定大小为n的缓存区。生产者的工做是生产一段数据,只有缓冲区没满时,生产者才能把消息放入到缓冲区,不然必须等待,如此反复。只有缓冲区非空时,消费者才能从中取出数据,一次消费一段数据,不然必须等待。问题的核心是:ide
解决生产者消费者问题其实是要解决线程间互斥关系和同步关系问题。因为缓冲区是临界资源,一个时刻只容许一个生产者放入消息,或者一个消费者从中取出消息。这里须要解决一个互斥访问的问题。同时生产者和消费者又是一个相互协做的关系,只有生产者生产以后,消费者才能消费,因此还须要解决一个同步的问题
函数
/* 生成者线程入口 */ void producer_thread_entry(void* parameter) { int cnt = 0; /* 运行100次 */ while( cnt < 100) { /* 获取一个空位 */ rt_sem_take(&sem_empty, RT_WAITING_FOREVER); /* 修改array内容,上锁 */ rt_sem_take(&sem_lock, RT_WAITING_FOREVER); array[set%MAXSEM] = cnt + 1; rt_kprintf("the producer generates a number: %d\n", array[set%MAXSEM]); set++; rt_sem_release(&sem_lock); /* 发布一个满位 */ rt_sem_release(&sem_full); cnt++; /* 暂停一段时间 */ rt_thread_delay(50); } rt_kprintf("the producer exit!\n"); } /* 消费者线程入口 */ void consumer_thread_entry(void* parameter) { rt_uint32_t no; rt_uint32_t sum; /* 第n个线程,由入口参数传进来 */ no = (rt_uint32_t)parameter; sum = 0; while(1) { /* 获取一个满位 */ rt_sem_take(&sem_full, RT_WAITING_FOREVER); /* 临界区,上锁进行操做 */ rt_sem_take(&sem_lock, RT_WAITING_FOREVER); sum += array[get%MAXSEM]; rt_kprintf("the consumer[%d] get a number: %d\n", no, array[get%MAXSEM] ); get++; rt_sem_release(&sem_lock); /* 释放一个空位 */ rt_sem_release(&sem_empty); /* 生产者生产到100个数目,中止,消费者线程相应中止 */ if (get == 100) break; /* 暂停一小会时间 */ rt_thread_delay(10); } rt_kprintf("the consumer[%d] sum is %d \n ", no, sum); rt_kprintf("the consumer[%d] exit!\n"); } int semaphore_producer_consumer_init() { /* 初始化3个信号量 */ rt_sem_init(&sem_lock , "lock", 1, RT_IPC_FLAG_FIFO); rt_sem_init(&sem_empty, "empty", MAXSEM, RT_IPC_FLAG_FIFO); rt_sem_init(&sem_full , "full", 0, RT_IPC_FLAG_FIFO); /* 建立线程1 */ producer_tid = rt_thread_create("producer", producer_thread_entry, RT_NULL, /* 线程入口是producer_thread_entry, 入口参数是RT_NULL */ THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE); if (producer_tid != RT_NULL) rt_thread_startup(producer_tid); else tc_stat(TC_STAT_END | TC_STAT_FAILED); /* 建立线程2 */ consumer_tid = rt_thread_create("consumer", consumer_thread_entry, RT_NULL, /* 线程入口是consumer_thread_entry, 入口参数是RT_NULL */ THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE); if (consumer_tid != RT_NULL) rt_thread_startup(consumer_tid); else tc_stat(TC_STAT_END | TC_STAT_FAILED); return 0; }
互斥量控制块是操做系统用于管理互斥量的一个数据结构。ui
struct rt_mutex { struct rt_ipc_object parent; /* IPC对象继承而来 */ rt_uint16_t value; /* 只有LOCK和UNLOCK两种值 */ rt_uint8_t original_priority; /* 上一次得到该锁的线程的优先级 */ rt_uint8_t hold; /* 该线程获取了多少次该互斥锁 */ struct rt_thread *owner; /* 当前拥有该锁的线程句柄 */ } 静态互斥量:struct rt_mutex static_mutex; 动态互斥量:rt_mutex_t dynamic_mutex;
静态互斥量 rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag); //RT_IPC_FIFO RT_IPC_FLAG_PRIO rt_err_t rt_mutex_detach(rt_mutex_t mutex);
动态互斥量 rt_mutex rt_mutex_create(const char *name, rt_uint8_t flag); rt_err_t rt_mutex_delete(rt_mutex_t mutex);
只能在线程中调用,且同一个线程可以take屡次同一个互斥量,其成员hold+1 rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time) // RT_WAITING_FOREVER = -1
只能在线程中调用,不能在中断中调用。必须同一个线程获取的同一个互斥量,才能在该线程释放该互斥量 rt_err_t rt_mutex_release(rt_mutex_t mutex)
当一个高优先级线程试图经过某种互斥IPC对象机制访问共享资源时,若是该IPC对象已经被一个低优先级的线程所持有,并且这个低优先级线程运行过程当中可能又被其余一些中等优先级的线程抢占,所以形成高优先级线程被许多具备较低优先级的线程阻塞的状况。致使高优先级的实时性得不到保证操作系统
在RT-Thread中,经过互斥量的优先级继承算法,可有有效解决优先级翻转问题。优先级继承是指提升某个占有某种共享资源的低优先级线程优先级,使之与全部等待该资源的线程中优先级最高的那个线程的优先级相等,从而获得更快地执行而后释放共享资源,当这个低优先级线程释放该资源时,优先级从新回到初始设定值。继承优先级的线程,避免了系统共享资源被任何中间优先级的线程抢占线程
优先级翻转线向提醒编程人员对共享资源进行互斥访问的代码段应尽可能短。让低优先级线程尽快完成工做,释放共享资源
本文做者: CrazyCatJack
本文连接: https://www.cnblogs.com/CrazyCatJack/p/14408842.html
版权声明:本博客全部文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
关注博主:若是您以为该文章对您有帮助,能够点击文章右下角推荐一下,您的支持将成为我最大的动力!