03 FreeRTOS 同步互斥与通信

1、同步与互斥

        一句话理解同步与互斥:我等你用完厕所,我再用厕所。

        什么叫同步?就是:哎哎哎,我正在用厕所,你等会。

        什么叫互斥?就是:哎哎哎,我正在用厕所,你不能进来。

        同步与互斥经常放在一起讲,是因为它们之的关系很大,“互斥"操作可以使用“同步"来实现。我"等"你用完厕所,我再用厕所。这不就是用“同步"来实现“互斥吗?

        设置一段伪代码如下:

void 抢厕所(void)
{
    if(有人在用) 我眯一会;
    用厕所;
    喂,醒醒,有人要用厕所吗;
}

        假设有A、B两人早起抢厕所,A先行一步占用了;B慢了一步,于是就眯一会;当A用完后叫醒B,B也就愉快地上厕所了。

        在这个过程中,A、B是互斥地访问“厕所",“厕所'被称之为临界资源。我们使用了“休眠-唤醒"的同步机制实现了临界资源"的“互斥访问"。

        同一时间只能有一个人使用的资源,被称为临界资源。比如任务A、B都要使用串口来打印,串口就是临界资源。如果A、B同时使用串口,那么打印出来的信息就是A、B混杂,无法分辨。所以使用串口时,应该是这样:A用完,B再用;B用完,A再用。

2、自己实现同步例子:有缺陷

static int sum = 0;
static volatile int flagCalcEnd = 0;

void Task1Function( void * param)
{
	volatile int i = 0;	//使用volatile修饰,让系统不要去优化这个变量
	while(1){
		for(i = 0; i < 10000000; i++){
			sum++;
		}
		//printf("1");
		flagCalcEnd = 1;
		vTaskDelete(NULL);
	}
}

void Task2Function( void * param)
{
	while(1){
		if(flagCalcEnd){
			printf("sum = %d\r\n", sum);
		}
		//printf("2");
	}
}

        当任务一一直在累加时,任务二还一直在竞争cpu资源,此时完成10000000次累加用了4s。

        如果注释掉任务二,此时完成10000000次累加用了2s。

        因此可以看出在任务二中使用循环检测某个变量,来实现同步的方法是有缺陷的,如果在任务二中让其在等待的过程中,让任务二进入blocked状态,不要让其去抢占cpu资源,这个程序的运行效率就会大幅提高。

3、自己实现互斥例子:有缺陷

void TaskGenericFunction( void * param)
{
	while(1){
		printf("%s\r\n", (char *)param);
	}
}


//main函数中
xTaskCreate(TaskGenericFunction, "Task3", 100, "Task 3 is running", 1, NULL);
xTaskCreate(TaskGenericFunction, "Task4", 100, "Task 3 is running", 1, NULL);

        可以发现任务三和任务四打印的语句掺杂在一起,任务三的语句还没打印完就被打断了,没有能在打印的时候互斥的去独占整个串口

        在这基础上去做出改进,让打印信息时可以独占串口。但是从结果可以看出此时只有一个任务在一直执行,另一个任务抢不到cpu资源。

static volatile int flagUARTused = 0;

void TaskGenericFunction( void * param)
{
	while(1){
		if(!flagUARTused){
			flagUARTused = 1;
			printf("%s\r\n", (char *)param);
			flagUARTused = 0;
		}	
	}
}

        如果想要另一个任务也能抢到资源,可以在上面的基础上加个delay函数。 

void TaskGenericFunction( void * param)
{
	while(1){
		if(!flagUARTused){
			flagUARTused = 1;
			printf("%s\r\n", (char *)param);
			flagUARTused = 0;
			vTaskDelay(1);
		}	
	}
}

        至此,这个代码看似没问题,很好的完成了互斥的作用。 但是这个代码是有很大隐患的,因为在多任务系统中,使用全局变量来实现互斥是有隐患的。

        假如任务三执行到flagUARTused=1;时被调度切换出去了,那么此时任务四就过来执行了,如果任务四在运行到flagUARTused=1;时也被调度切换出去了,那么后面如果两个任务都恢复过来,那么这两个任务都可以执行之后的语句,此时就无法通过flagUARTused来实现互斥的作用了。

4、FreeRTOS的解决方案

4.1 队列(queue,FIFO)

        里面可以放任意数据,可以放多个数据

        任务、ISR都可以放入数据;任务、ISR都可以从中读出数据

4.2 事件组(event grtoup)

        一个事件用一bit表示,1表示事件发生了,0表示事件没发生

        可以用来表示事件、事件的组合发生了,不能传递数据

        有广播效果:事件或事件的组合发生了,等待它的多个任务都会被唤醒

4.3 信号量(semaphore)

        核心是"计数值"

        任务、ISR释放信号量时让计数值加1

        任务、ISR获得信号量时,让计数值减1

4.4 任务通知(task notification)

        核心是任务的TCB里的数值

        会被覆盖

        发通知给谁?必须指定接收任务

        只能由接收任务本身获取该通知

4.5 互斥量(mutex)

        数值只有0或1

        谁获得互斥量,就必须由谁释放同一个互斥量

  • 29
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值