原创:我跟你一起学MQX(三):互斥量
本帖最后由 wangpengcheng 于 2014-9-9 14:05 编辑前几天回老家,坐火车,也怪我自己,上车之前吧,有点想上厕所的冲动,但是又怕到时候挤不上车,就忍着,反正车上有厕所,上车再解决吧!结果上车后,安排好座位,行李,直奔厕所,这回郁闷了,厕所关着门,有人占用!唉,算了再憋回吧,但还得回去看行李。过了回再来看,还是有人,再回去看住行李。如此来回几趟!突然我发现列车的前后都有厕所是否为空的指示灯啊,绿色的时候说明没有人,红色的时候说明有人,于是我就不用再来回跑了,盯着灯看,一旦变绿了,赶紧冲过去解决了问题,这个爽啊!
呵呵,同学们,后来我想了,这灯是什么呢?这不就是互斥量吗?共同资源,有一方占用,那么可将占用互斥量,其它想用,不好意思,不能用,想用你得等我将互斥量释放出来,这不跟列车上厕所的灯一样一样的吗?
好吧,我想现在我知道什么是互斥量了!下面我就刚才的例子做用代码描述一下吧,虽然例子有点不文明,但比较形象!{:titter:}
首先,我建一个旅客属性的结构体:
typedef struct _PassengerAttribute
{
char Name; //旅客名称
char *Food; //旅客自备的食物
char *Drinks; //旅客自备的饮料
uint32_t WaitTime; //旅客吃完喝完要等这么长时间才去厕所
uint32_t UseToiletTime; //旅客在厕所里也需要这时间进行解决啊
}PassengerAttribute, *PassengerAttribute_PTR;
好吧,现在我们看看旅客A跟B都带了什么!
假如旅客A家里比较有钱,带的是汉堡、可乐,但是它消化系统不好,平均需要1S就得占用一次厕所,一次占用2S钟时间。
PassengerAttribute PassengerA = {'A', "Hamburger", "Cola", 1000, 2000 };
旅客B家境稍贫寒一点,带的是馒头跟凉白开,但旅客B由于经常劳动,身体不错,他平均1.5S去一次厕所,而且时间很快,0.5S就解决了!
PassengerAttribute PassengerB = {'B', "Steamed buns", "Water", 1500, 500 };
现在旅客已经准备好了,我开始准备列车了,准备列车需要两个元素,一个是厕所的互斥量:
MUTEX_STRUCT ToiletMutex;
另一个就是一个过程,过程需要先初始化互斥量,然后请旅客上车,那我就用一个初始化任务来解决吧:
void MainTask(uint32_t para)
{
MUTEX_ATTR_STRUCT mutexattr; //互斥量属性,这个去mutex.h文件里找吧,跟前面两节一样,它一样有好几个属性,同样我也没用几个,呵呵,我人懒了!
/* Initialize mutex attributes: */
if (_mutatr_init(&mutexattr) != MQX_OK) { //初始化互斥量属性
printf("Initializing mutex attributes failed.\n");
_mqx_exit(0);
}
/* Initialize the mutex: */
if (_mutex_init(&ToiletMutex, &mutexattr) != MQX_OK) { //初始化互斥量
printf("Initializing print mutex failed.\n");
_mqx_exit(0);
}
/* Create the print tasks */
_task_create(0, PASG_TASK, (uint32_t)&PassengerA); //旅客A上车了
_task_create(0, PASG_TASK, (uint32_t)&PassengerB); //旅客B上车了
}
从上面的任务中,可以看出,其实我创建了两个同样的任务,只是输入参数不同了,为什么呢?因为旅客的行为都是一样的,只是他们的属性不一样罢了,我这么做的话,有个好处,可以少写一些代码!{:titter:}
下面旅客上车后就开始了他们的动作跟行为:
//吃东西
void Eat(PassengerAttribute_PTR Passenger)
{
printf("Passenger %c eat %s!\r\n", Passenger->Name, Passenger->Food);
}
//喝饮料
void Drink(PassengerAttribute_PTR Passenger)
{
printf("Passenger %c drink %s!\r\n", Passenger->Name, Passenger->Drinks);
}
//用厕所
void UseTheToilet(PassengerAttribute_PTR Passenger)
{
if (_mutex_lock(&ToiletMutex) != MQX_OK) { //进厕所后先锁门
printf("Mutex lock failed.\n");
_mqx_exit(0);
}
printf("Passenger %c use the toilet %d time!\r\n", Passenger->Name, Passenger->UseToiletTime);
_time_delay(Passenger->UseToiletTime); //占坑时间
_mutex_unlock(&ToiletMutex); //出厕所后把门打开
printf("Passenger %c use the toilet end!\r\n", Passenger->Name);
}
void PassengerTask(uint32_t para)
{
PassengerAttribute_PTRPassenger = (PassengerAttribute_PTR)para;
while(1)
{
Eat(Passenger); //吃东西
Drink(Passenger); //喝饮料
_time_delay(Passenger->WaitTime); //等待
UseTheToilet(Passenger); //上厕所
}
}
呵呵,看到了吧?进了厕所要锁门,出了厕所打门打开,方便后面的人继续用啊!
现在我们把所需要的元素都定义好了,就可以开始了!
好吧,我忘记铁路局了,铁路局还没定义呢,当然铁路局就是我们的任务列表, 这个相信已经不用我再说了吧?
const TASK_TEMPLATE_STRUCTMQX_template_list[] =
{
/* Task Index, Function, Stack,Priority, Name, Attributes, Param, Time Slice */
{ MAIN_TASK, MainTask, 1500, 8, "main",MQX_AUTO_START_TASK, 0, 0 },
{ PASG_TASK, PassengerTask, 1500, 9, "pasg",MQX_USER_TASK , 0, 0},
{ 0 }
};
OK,现在一切准备就绪,让我们的列车开始运行吧:
从结果中,我们可以看出,不管是A还是B,在占用厕所的时候,别人就算着急了,也上不了!唉,下次我上车前得先解决了再上,教训啊{:titter:}
什么?还有API没说,好吧,呵呵,所有API函数以及常量都在mutex.h文件中,一般人我不告诉他!
最后照例是源码:
活学活用的好榜样,赞一个! wycox 发表于 2014-9-9 13:40
活学活用的好榜样,赞一个!
谢谢啊!呵呵! 楼主这个生动的亲身经历讲解程序,简直神了!1 sdlibin007 发表于 2014-9-9 13:45
楼主这个生动的亲身经历讲解程序,简直神了!1
只是觉得这个例子用来解释互斥量比较形像,呵呵! wangpengcheng 发表于 2014-9-9 13:48
只是觉得这个例子用来解释互斥量比较形像,呵呵!
楼主确实神,我都做了四年的火车了,厕所灯也见识了很多次了,但是从来没想到与代码联系起来! 跟着楼主学习,这样学的更快。 sdlibin007 发表于 2014-9-9 13:52
楼主确实神,我都做了四年的火车了,厕所灯也见识了很多次了,但是从来没想到与代码联系起来! ...
也不是随便找的,也想了好久,呵呵,觉得这个可以很明白的说明问题! 本帖最后由 wangpengcheng 于 2014-9-9 14:01 编辑
32MCU 发表于 2014-9-9 13:57
跟着楼主学习,这样学的更快。
一起学习吧,训龙高手,呵呵! 看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。 你真调皮,举得例子已经很明白的讲了什么是互斥量,非常生动形象。 rockyyangyang 发表于 2014-9-9 14:04
你真调皮,举得例子已经很明白的讲了什么是互斥量,非常生动形象。
能理解说明我没白做,呵呵! 步之道 发表于 2014-9-9 14:02
看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。
有问题可以讨论哈 wangpengcheng 发表于 2014-9-9 14:06
有问题可以讨论哈
在公司不方便细看,晚上回去看,有不明白的向楼主请教,哈哈,千万别嫌烦。 赞,让人能够清晰互斥量的基本意思 步之道 发表于 2014-9-9 14:16
在公司不方便细看,晚上回去看,有不明白的向楼主请教,哈哈,千万别嫌烦。 ...
怎么会,凡我了解的,一定会告诉你 bestlong22 发表于 2014-9-9 14:17
赞,让人能够清晰互斥量的基本意思
谢谢点赞 LZ,你这个讲解真是通俗易懂,“通透”。 旅客A得虚脱了;
楼主讲的很不错。等待下一讲, 呵呵 楼主解释的挺有意思 用例讲解,楼主有当老师的天分啊 qwert1213131 发表于 2014-9-9 17:18
旅客A得虚脱了;
楼主讲的很不错。等待下一讲,
呵呵,脱不了,人家吃汉堡,喝可乐呢! lzl000 发表于 2014-9-9 17:31
用例讲解,楼主有当老师的天分啊
谢谢夸奖,呵呵,关键是大家能弄明白怎么回事! 楼主,你可以出一本书了。任哲板的ucos讲的也不过你这个水平。很生动形象,而且北航的一本书也很不错 好东西啊 一定要顶一个 楼主,没有说到互斥量的两特性:1、同一个进程lock和unlock。2、互斥量的两态性。 楼主真乃神人也~ 楼主的“跟我学MQX”系列教程不错,通俗易懂,这个也同样适用于其他的RTOS。 我觉得这两点应该着重点出来,因为很容易和上一次讲的信号量混淆。从而导致互斥量的特点不够鲜明。 楼主真是善于思考。 楼主的讲解有风趣又有内涵,挺期待哈!楼楼接下来的更新都会看的 楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点明 步之道 发表于 2014-9-9 21:18
楼主,没有说到互斥量的两特性:1、同一个进程lock和unlock。2、互斥量的两态性。 ...
同一个进程的lock与unlock倒是用到过,跟开关中断是一个道理!但互斥量的两态性还真没听说过,愿闻其详? 能讲到别人听了很懂了,说明你也是大师 步之道 发表于 2014-9-9 21:25
我觉得这两点应该着重点出来,因为很容易和上一次讲的信号量混淆。从而导致互斥量的特点不够鲜明。 ...
感觉互斥量可以用信号量代替,只要不使用信号量的计数功能就可以了!但一般情况还是建议考虑自己项目的具体情况来使用,以前就碰到过信号量当互斥量用,但因为初始化值的问题出现BUG! nishuizhou 发表于 2014-9-9 22:39
能讲到别人听了很懂了,说明你也是大师
我才不是什么大师,只是能简单应用起来!呵呵,一些深层次的东西都缺少研究! wuguoyan 发表于 2014-9-9 21:24
楼主的“跟我学MQX”系列教程不错,通俗易懂,这个也同样适用于其他的RTOS。 ...
是的,感觉OS应用上都差不多,都是这些个组件! wxfje 发表于 2014-9-9 22:07
楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点 ...
如果你方便的话,把自己的具体想法也贴出来吧,我们一起学习! wangpengcheng 发表于 2014-9-9 22:37
同一个进程的lock与unlock倒是用到过,跟开关中断是一个道理!但互斥量的两态性还真没听说过,愿闻其详? ...
互斥量值只能为0/1,就是对应lock与unlock这两个状态。我开了另一个帖子:【交流学习】理解互斥量和信号量 欢迎拍砖,别打脸,哈哈!
http://www.amobbs.com/thread-5595285-1-1.html
因为我看了你的帖子后我觉的没有写出互斥量的特点,任意定义一个变量都可以做到你所说的互斥量的功能。 wxfje 发表于 2014-9-9 22:07
楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点 ...
感谢坛友顶我,不过楼主写的非常好了,要是我估计没这么大耐心。哈哈,懒了 比喻不错 你这个是二值信号量,哪里体现互斥了 ludikn 发表于 2014-9-9 23:39 你这个是二值信号量,哪里体现互斥了
楼主没有重点拎出来讲,不过应用的时候用到了互斥量的特性。 互斥量有优先级继承,解决了优先级翻转的问题 ludikn 发表于 2014-9-9 23:39
你这个是二值信号量,哪里体现互斥了
能说说你理解的互斥量是什么样子的吗? 0flame0 发表于 2014-9-10 08:37
互斥量有优先级继承,解决了优先级翻转的问题
能举个例子吗? wangpengcheng 发表于 2014-9-10 10:35
能举个例子吗?
有优先级依次降低的三个线程A、B、C,假设A,B挂起,C正在运行,此时C开始使用共享资源。此时A转为就绪态,由于它比C优先级
高,所以立即执行。当A要使用该共享资源,由于其正在被C使用,那么A将被挂起切换到C运行。假设此时B进入就绪态,因为B
的优先级比C高,B开始运行,直到其运行完毕后C才开始运行。但是因为C依然占有共享资源,A必须等到C释放该资源后才能运行,这
样B虽然优先级比A低但是却先运行。
优先级继承就是C在占有资源时优先级提升到A的优先级,释放该资源后恢复到之前优先级,保证A在B之前运行。 很正式的名词解说往往费力不讨好,能跟恰当的比喻联系起来就事半功倍了。
还是喜欢比喻,能让人理解透彻,谢谢楼主和zulu 0flame0 发表于 2014-9-10 11:40
有优先级依次降低的三个线程A、B、C,假设A,B挂起,C正在运行,此时C开始使用共享资源。此时A转为就绪 ...
我感觉这个过程好是系统在做的吧?不用我们操心,是这样吗? 楼主真是个好老师~~ 知道互斥量 是干嘛的了, 实际项目中还真没想好如何用。貌似还没遇到有冲突的东西。
楼主举例很形象。 street 发表于 2014-9-10 15:42
知道互斥量 是干嘛的了, 实际项目中还真没想好如何用。貌似还没遇到有冲突的东西。
楼主举例很形象。 ...
其实我就是感觉在任务中使用共同的资源,而且在使用过程中任务可能会释放CPU的时候,就必须用! 学习了,比喻很恰当,浅显易懂,感谢分享。 好东西啊学习 wangpengcheng 发表于 2014-9-10 16:05
其实我就是感觉在任务中使用共同的资源,而且在使用过程中任务可能会释放CPU的时候,就必须用! ...
如果我 有一个AD 芯片 有两个任务 需要获取AD的数据,但是AD每1S才能完成一次转换。
这样的话用互斥量 我感觉不妥。
有什么其他好的方法没有? wangpengcheng 发表于 2014-9-10 15:30
我感觉这个过程好是系统在做的吧?不用我们操心,是这样吗?
对,不过也可以写个例子看看具体结果 楼主厉害, 很有用,MARK。 讲的不错.....很容易让人理解... street 发表于 2014-9-10 16:55
如果我 有一个AD 芯片 有两个任务 需要获取AD的数据,但是AD每1S才能完成一次转换。
这样的话用互斥量...
你这个不需要用互斥量啊,因为任务在读AD芯片的时候不会让出CPU的,它不会说我发一个脉冲,然后等200MS,呵呵!你这个可以不用任务东西,直接读取就可以了,如果真要做,把AD做成驱动就行,意思就是有open\close\read\write\ioctl几个函数把AD功能包起来! 0flame0 发表于 2014-9-10 16:59
对,不过也可以写个例子看看具体结果
{:lol:} 没必要动那个脑子了,呵呵,入门级的简单点就行!像那些东西入门后自己研究 学习了,赞一项下。 wangpengcheng 发表于 2014-9-9 22:45
如果你方便的话,把自己的具体想法也贴出来吧,我们一起学习!
迟了,那位兄弟已经发了{:mad:} wangpengcheng 发表于 2014-9-10 18:10
没必要动那个脑子了,呵呵,入门级的简单点就行!像那些东西入门后自己研究 ...
其实你给一个用法就够了,多搞些例程,使用按键,LED , 串口,这三样基本上能把MQX的大部分功能实现了;
你一上来讲原理是没用的,这个东西是必须在实践中出真知,哪怕是理论上懂了,真用起来,依然是手忙脚乱,所以一开始直接给例程,跑范例;
PS : 原来开始搞OS的时候,我看互斥量,然后看咋用,咋弄,原理,都明明白白的,可真用起来,不晓得咋用了,直到某年某日,用多了,突然醒梧,这尼玛的三个字就表明了它的意图啊,"互斥"太精僻了,那为什么之前明明也是叫互斥量,可就是不明白呢? 生动,顶起来,楼主好样的
页:
[1]