文章目录
- 资源管理
- 一、简述
-
- 二、保证原子操作的二种方式
-
- 三、互斥量(mutex)
-
- 四、守护任务
- 零: 线程间同步的名字解释
-
资源管理
一、简述
个人总结
就是通过一些操作,防止并行访问资源的时候,出现脏读藏写的管理称之为资源管理。
二、保证原子操作的二种方式
1. 临界区
临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。
每个进程中访问临界资源的那段代码称为临界区(Critical Section)(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
把某优先级以下的中断全部关闭。进行原子操作。
把中断全部关掉,或是关掉优先级在 、configMAX_SYSCAL_INTERRUPT_PRIORITY
及以下的中断——依赖于具体使用的 FreeRTOS 移植。抢占式上下文切换只可能在某个中断中完成,所以调用 taskENTER_CRITICAL()
的任务可以在中断关闭的时段一直保持运行态,直到退出临界区.
API
临界区必须只具有很短的时间,否则会反过来影响中断响应时间。在每次调用 taskENTER_CRITICAL()
之后,必须尽快地配套调用一个 taskEXIT_CRITICAL()
, 读写这种比较耗费时间的操作,尽量不要使用临界区这种保护机制。
void vPrintString( const portCHAR *pcString )
{
taskENTER_CRITICAL();
{
printf( "%s", pcString );
fflush( stdout );
}
taskEXIT_CRITICAL();
if( kbhit() )
{
vTaskEndScheduler();
}
}
1)调用 rt_hw_interrupt_disable() 进入临界区,调用 rt_hw_interrupt_enable() 退出临界区;
2)调用 rt_enter_critical() 进入临界区,调用 rt_exit_critical() 退出临界区。
2. 挂起调度器
直接把任务调度器给挂起锁死,这个时候外部中断虽然使能,但是无法操作。
需要创建临界区除了 FreeRTOS
操作系统提供的函数外,还可以通过挂起调度器的操作来创建一个临界区。但是重新唤醒(resuming, or un-suspending)调度器是一个费时的操作。所以评估使用临界区函数来实现原子操作还是挂起调度器实现原子操作,需要结合实际情况。
在调度器处于挂起状态时,不能调用 FreeRTOS API 函数。
void vPrintString( const portCHAR *pcString )
{
vTaskSuspendScheduler();
{
printf( "%s", pcString );
fflush( stdout );
}
xTaskResumeScheduler();
if( kbhit() )
{
vTaskEndScheduler();
}
}
个人总结
就是将外部中断给屏蔽,原本的操作就不会被打断,这样操作起来就具有原子性了。
三、互斥量(mutex)
互斥量是一种特殊的二值信号量,用于控制在两个或多个任务间访问共享资源。
static void prvNewPrintString( const portCHAR *pcString )
{
xSemaphoreTake( xMutex, portMAX_DELAY );
{
printf( "%s", pcString );
fflush( stdout );
}
xSemaphoreGive( xMutex );
if( kbhit() )
{
vTaskEndScheduler();
}
}
int main( void )
{
xMutex = xSemaphoreCreateMutex();
srand( 567 );
if( xMutex != NULL )
{
xTaskCreate( prvPrintTask, "Print1", 1000,
"Task 1 ******************************************\r\n", 1, NULL );
xTaskCreate( prvPrintTask, "Print2", 1000,
"Task 2 ------------------------------------------\r\n", 2, NULL );
vTaskStartScheduler();
}
for( ;; );
}
优先级反转
高优先级任务被低优先级任务阻塞推迟的行为被称为”优先级反转”。
优先级反转可能会产生重大问题。但是在一个小型的嵌入式系统中,通常可以在设计阶段就通过规划好资源的访问方式避免出现这个问题。’
优先级继承
优先级继承是最小化优先级反转负面影响的一种方案-其并不能修正优先级反转带来的问题,仅仅是减小优先级反转的影响。优先级继承
使得系统行为的数学分析更为复杂,所以如果可以避免的话,并不建议系统实现对优先
级继承有所依赖。
优先级继承暂时地将互斥量持有者的优先级提升至所有等待此互斥量的任务所具有的最高优先级。
’
死锁
- 任务 A 执行,并成功获得了互斥量 X。
- 任务 A 被任务 B 抢占。
- 任务 B 成功获得了互斥量 Y,之后又试图获取互斥量 X——但互斥量 X 已经被任务 A 持有,所以对任务 B 无效。任务 B 选择进入阻塞态以等待互斥量 X 被释放。
- 任务 A 得以继续执行。其试图获取互斥量 Y——但互斥量 Y 已经被任务 B持有而对任务 A 无效。任务 A 也选择进入阻塞态以等待互斥量 Y 被释放。
任务 A 在等待一个被任务 B 持有的互斥量,而任务 B 也在等待一个被任务 A 持有的互斥量。死锁于是发生,因为两个任务都不可能再执行下
去了。
四、守护任务
-
守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务
-
守护任务提供了一种干净利落的方法来实现互斥功能,而不用担心会发生优先级反转和死锁。
守护任务使用了一个 FreeRTOS 队列来对终端实现串行化访问。该任务内部实现不必考虑互斥,因为它是唯一能够直接访问终端的任务。
有些资源只有守护线程才能访问,使用的时候发消息给守护线程,让守护线程去访问资源,从而避免死锁和优先级反转的问题
零: 线程间同步的名字解释
1. 信号量
信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量 引用自: 百度百科-信号量
互斥量和信号量
-
互斥量用于线程的互斥,信号量用于线程的同步。
这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
2.互斥量无法保证线程对资源的有序访问,信号量可以。
二值信号量和互斥锁的区别
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)