搜索
bottom↓
回复: 64

原创:我跟你一起学MQX(三):互斥量

[复制链接]

出0入0汤圆

发表于 2014-9-9 13:28:33 | 显示全部楼层 |阅读模式
本帖最后由 wangpengcheng 于 2014-9-9 14:05 编辑

前几天回老家,坐火车,也怪我自己,上车之前吧,有点想上厕所的冲动,但是又怕到时候挤不上车,就忍着,反正车上有厕所,上车再解决吧!结果上车后,安排好座位,行李,直奔厕所,这回郁闷了,厕所关着门,有人占用!唉,算了再憋回吧,但还得回去看行李。过了回再来看,还是有人,再回去看住行李。如此来回几趟!突然我发现列车的前后都有厕所是否为空的指示灯啊,绿色的时候说明没有人,红色的时候说明有人,于是我就不用再来回跑了,盯着灯看,一旦变绿了,赶紧冲过去解决了问题,这个爽啊!

呵呵,同学们,后来我想了,这灯是什么呢?这不就是互斥量吗?共同资源,有一方占用,那么可将占用互斥量,其它想用,不好意思,不能用,想用你得等我将互斥量释放出来,这不跟列车上厕所的灯一样一样的吗?

好吧,我想现在我知道什么是互斥量了!下面我就刚才的例子做用代码描述一下吧,虽然例子有点不文明,但比较形象!

首先,我建一个旅客属性的结构体:
  1. typedef struct _PassengerAttribute
  2. {
  3.     char Name;                          //旅客名称
  4.     char *Food;                         //旅客自备的食物
  5.     char *Drinks;                      //旅客自备的饮料
  6.     uint32_t WaitTime;              //旅客吃完喝完要等这么长时间才去厕所
  7.     uint32_t UseToiletTime;      //旅客在厕所里也需要这时间进行解决啊
  8. }PassengerAttribute, *PassengerAttribute_PTR;
复制代码


好吧,现在我们看看旅客A跟B都带了什么!
假如旅客A家里比较有钱,带的是汉堡、可乐,但是它消化系统不好,平均需要1S就得占用一次厕所,一次占用2S钟时间。
  1. PassengerAttribute PassengerA = {  'A', "Hamburger", "Cola", 1000, 2000 };
复制代码

旅客B家境稍贫寒一点,带的是馒头跟凉白开,但旅客B由于经常劳动,身体不错,他平均1.5S去一次厕所,而且时间很快,0.5S就解决了!
  1. PassengerAttribute PassengerB = {  'B', "Steamed buns", "Water", 1500, 500 };
复制代码


现在旅客已经准备好了,我开始准备列车了,准备列车需要两个元素,一个是厕所的互斥量:
  1. MUTEX_STRUCT ToiletMutex;
复制代码

另一个就是一个过程,过程需要先初始化互斥量,然后请旅客上车,那我就用一个初始化任务来解决吧:
  1. void MainTask(uint32_t para)
  2. {
  3.     MUTEX_ATTR_STRUCT mutexattr;                        //互斥量属性,这个去mutex.h文件里找吧,跟前面两节一样,它一样有好几个属性,同样我也没用几个,呵呵,我人懒了!
  4.     /* Initialize mutex attributes: */
  5.     if (_mutatr_init(&mutexattr) != MQX_OK) {        //初始化互斥量属性
  6.         printf("Initializing mutex attributes failed.\n");
  7.         _mqx_exit(0);
  8.     }
  9.     /* Initialize the mutex: */
  10.     if (_mutex_init(&ToiletMutex, &mutexattr) != MQX_OK) {   //初始化互斥量
  11.         printf("Initializing print mutex failed.\n");
  12.         _mqx_exit(0);
  13.     }
  14.     /* Create the print tasks */
  15.     _task_create(0, PASG_TASK, (uint32_t)&PassengerA);        //旅客A上车了
  16.     _task_create(0, PASG_TASK, (uint32_t)&PassengerB);       //旅客B上车了
  17. }
复制代码


从上面的任务中,可以看出,其实我创建了两个同样的任务,只是输入参数不同了,为什么呢?因为旅客的行为都是一样的,只是他们的属性不一样罢了,我这么做的话,有个好处,可以少写一些代码!

下面旅客上车后就开始了他们的动作跟行为:
  1. //吃东西
  2. void Eat(PassengerAttribute_PTR Passenger)
  3. {
  4.     printf("Passenger %c eat %s!\r\n", Passenger->Name, Passenger->Food);
  5. }
  6. //喝饮料
  7. void Drink(PassengerAttribute_PTR Passenger)
  8. {
  9.     printf("Passenger %c drink %s!\r\n", Passenger->Name, Passenger->Drinks);
  10. }
  11. //用厕所
  12. void UseTheToilet(PassengerAttribute_PTR Passenger)
  13. {
  14.     if (_mutex_lock(&ToiletMutex) != MQX_OK) {                                //进厕所后先锁门
  15.         printf("Mutex lock failed.\n");
  16.         _mqx_exit(0);
  17.     }
  18.     printf("Passenger %c use the toilet %d time!\r\n", Passenger->Name, Passenger->UseToiletTime);
  19.     _time_delay(Passenger->UseToiletTime);                                //占坑时间
  20.     _mutex_unlock(&ToiletMutex);                                               //出厕所后把门打开
  21.     printf("Passenger %c use the toilet end!\r\n", Passenger->Name);
  22. }

  23. void PassengerTask(uint32_t para)
  24. {
  25.     PassengerAttribute_PTR  Passenger = (PassengerAttribute_PTR)para;
  26.     while(1)
  27.     {
  28.         Eat(Passenger);                                                //吃东西
  29.         Drink(Passenger);                                        //喝饮料
  30.         _time_delay(Passenger->WaitTime);                //等待
  31.         UseTheToilet(Passenger);                                //上厕所
  32.     }
  33. }
复制代码


呵呵,看到了吧?进了厕所要锁门,出了厕所打门打开,方便后面的人继续用啊!

现在我们把所需要的元素都定义好了,就可以开始了!

好吧,我忘记铁路局了,铁路局还没定义呢,当然铁路局就是我们的任务列表, 这个相信已经不用我再说了吧?
  1. const TASK_TEMPLATE_STRUCT  MQX_template_list[] =
  2. {
  3.     /* Task Index,   Function,   Stack,  Priority, Name,     Attributes,          Param, Time Slice */
  4.     { MAIN_TASK,   MainTask,        1500,   8,        "main",  MQX_AUTO_START_TASK, 0,     0 },
  5.     { PASG_TASK,   PassengerTask,   1500,   9,        "pasg",  MQX_USER_TASK      , 0,     0},
  6.     { 0 }
  7. };
复制代码


OK,现在一切准备就绪,让我们的列车开始运行吧:


从结果中,我们可以看出,不管是A还是B,在占用厕所的时候,别人就算着急了,也上不了!唉,下次我上车前得先解决了再上,教训啊

什么?还有API没说,好吧,呵呵,所有API函数以及常量都在mutex.h文件中,一般人我不告诉他!

最后照例是源码:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入4汤圆

发表于 2014-9-9 13:40:18 | 显示全部楼层
活学活用的好榜样,赞一个!

出0入0汤圆

 楼主| 发表于 2014-9-9 13:44:01 | 显示全部楼层
wycox 发表于 2014-9-9 13:40
活学活用的好榜样,赞一个!

谢谢啊!呵呵!

出0入0汤圆

发表于 2014-9-9 13:45:12 | 显示全部楼层
楼主这个生动的亲身经历讲解程序,简直神了!1

出0入0汤圆

 楼主| 发表于 2014-9-9 13:48:14 | 显示全部楼层
sdlibin007 发表于 2014-9-9 13:45
楼主这个生动的亲身经历讲解程序,简直神了!1

只是觉得这个例子用来解释互斥量比较形像,呵呵!

出0入0汤圆

发表于 2014-9-9 13:52:10 | 显示全部楼层
wangpengcheng 发表于 2014-9-9 13:48
只是觉得这个例子用来解释互斥量比较形像,呵呵!

楼主确实神,我都做了四年的火车了,厕所灯也见识了很多次了,但是从来没想到与代码联系起来!

出0入0汤圆

发表于 2014-9-9 13:57:39 | 显示全部楼层
跟着楼主学习,这样学的更快。

出0入0汤圆

 楼主| 发表于 2014-9-9 13:59:10 | 显示全部楼层
sdlibin007 发表于 2014-9-9 13:52
楼主确实神,我都做了四年的火车了,厕所灯也见识了很多次了,但是从来没想到与代码联系起来! ...

也不是随便找的,也想了好久,呵呵,觉得这个可以很明白的说明问题!

出0入0汤圆

 楼主| 发表于 2014-9-9 13:59:51 | 显示全部楼层
本帖最后由 wangpengcheng 于 2014-9-9 14:01 编辑
32MCU 发表于 2014-9-9 13:57
跟着楼主学习,这样学的更快。


一起学习吧,训龙高手,呵呵!

出0入0汤圆

发表于 2014-9-9 14:02:22 | 显示全部楼层
看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。

出0入0汤圆

发表于 2014-9-9 14:04:54 | 显示全部楼层
你真调皮,举得例子已经很明白的讲了什么是互斥量,非常生动形象。

出0入0汤圆

 楼主| 发表于 2014-9-9 14:06:13 | 显示全部楼层
rockyyangyang 发表于 2014-9-9 14:04
你真调皮,举得例子已经很明白的讲了什么是互斥量,非常生动形象。

能理解说明我没白做,呵呵!

出0入0汤圆

 楼主| 发表于 2014-9-9 14:06:46 | 显示全部楼层
步之道 发表于 2014-9-9 14:02
看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。

有问题可以讨论哈

出0入0汤圆

发表于 2014-9-9 14:16:56 | 显示全部楼层

在公司不方便细看,晚上回去看,有不明白的向楼主请教,哈哈,千万别嫌烦。

出0入0汤圆

发表于 2014-9-9 14:17:32 | 显示全部楼层
赞,让人能够清晰互斥量的基本意思

出0入0汤圆

 楼主| 发表于 2014-9-9 14:22:29 来自手机 | 显示全部楼层
步之道 发表于 2014-9-9 14:16
在公司不方便细看,晚上回去看,有不明白的向楼主请教,哈哈,千万别嫌烦。 ...

怎么会,凡我了解的,一定会告诉你

出0入0汤圆

 楼主| 发表于 2014-9-9 14:22:51 来自手机 | 显示全部楼层
bestlong22 发表于 2014-9-9 14:17
赞,让人能够清晰互斥量的基本意思

谢谢点赞

出100入101汤圆

发表于 2014-9-9 17:00:34 | 显示全部楼层
LZ,你这个讲解真是通俗易懂,“通透”。

出0入0汤圆

发表于 2014-9-9 17:18:27 | 显示全部楼层
旅客A得虚脱了;
楼主讲的很不错。等待下一讲,

出0入0汤圆

发表于 2014-9-9 17:26:12 | 显示全部楼层
呵呵   楼主解释的挺有意思

出0入0汤圆

发表于 2014-9-9 17:31:45 | 显示全部楼层
用例讲解,楼主有当老师的天分啊

出0入0汤圆

 楼主| 发表于 2014-9-9 17:47:09 | 显示全部楼层
qwert1213131 发表于 2014-9-9 17:18
旅客A得虚脱了;
楼主讲的很不错。等待下一讲,

呵呵,脱不了,人家吃汉堡,喝可乐呢!

出0入0汤圆

 楼主| 发表于 2014-9-9 17:47:43 | 显示全部楼层
lzl000 发表于 2014-9-9 17:31
用例讲解,楼主有当老师的天分啊

谢谢夸奖,呵呵,关键是大家能弄明白怎么回事!

出0入0汤圆

发表于 2014-9-9 20:39:57 | 显示全部楼层
楼主,你可以出一本书了。任哲板的ucos讲的也不过你这个水平。很生动形象,而且北航的一本书也很不错

出0入0汤圆

发表于 2014-9-9 20:54:45 | 显示全部楼层
好东西啊 一定要顶一个

出0入0汤圆

发表于 2014-9-9 21:18:52 | 显示全部楼层
楼主,没有说到互斥量的两特性:1、同一个进程lock和unlock。2、互斥量的两态性。

出0入0汤圆

发表于 2014-9-9 21:24:30 | 显示全部楼层
楼主真乃神人也~

出0入0汤圆

发表于 2014-9-9 21:24:32 | 显示全部楼层
楼主的“跟我学MQX”系列教程不错,通俗易懂,这个也同样适用于其他的RTOS。

出0入0汤圆

发表于 2014-9-9 21:25:42 | 显示全部楼层
我觉得这两点应该着重点出来,因为很容易和上一次讲的信号量混淆。从而导致互斥量的特点不够鲜明。

出0入0汤圆

发表于 2014-9-9 21:26:51 | 显示全部楼层
楼主真是善于思考。

出0入0汤圆

发表于 2014-9-9 21:42:12 | 显示全部楼层
楼主的讲解有风趣又有内涵,挺期待哈!楼楼接下来的更新都会看的

出0入0汤圆

发表于 2014-9-9 22:07:13 | 显示全部楼层
楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点明

出0入0汤圆

 楼主| 发表于 2014-9-9 22:37:27 | 显示全部楼层
步之道 发表于 2014-9-9 21:18
楼主,没有说到互斥量的两特性:1、同一个进程lock和unlock。2、互斥量的两态性。 ...

同一个进程的lock与unlock倒是用到过,跟开关中断是一个道理!但互斥量的两态性还真没听说过,愿闻其详?

出0入0汤圆

发表于 2014-9-9 22:39:46 | 显示全部楼层
能讲到别人听了很懂了,说明你也是大师

出0入0汤圆

 楼主| 发表于 2014-9-9 22:41:00 | 显示全部楼层
步之道 发表于 2014-9-9 21:25
我觉得这两点应该着重点出来,因为很容易和上一次讲的信号量混淆。从而导致互斥量的特点不够鲜明。 ...

感觉互斥量可以用信号量代替,只要不使用信号量的计数功能就可以了!但一般情况还是建议考虑自己项目的具体情况来使用,以前就碰到过信号量当互斥量用,但因为初始化值的问题出现BUG!

出0入0汤圆

 楼主| 发表于 2014-9-9 22:41:50 | 显示全部楼层
nishuizhou 发表于 2014-9-9 22:39
能讲到别人听了很懂了,说明你也是大师

我才不是什么大师,只是能简单应用起来!呵呵,一些深层次的东西都缺少研究!

出0入0汤圆

 楼主| 发表于 2014-9-9 22:43:24 | 显示全部楼层
wuguoyan 发表于 2014-9-9 21:24
楼主的“跟我学MQX”系列教程不错,通俗易懂,这个也同样适用于其他的RTOS。 ...

是的,感觉OS应用上都差不多,都是这些个组件!

出0入0汤圆

 楼主| 发表于 2014-9-9 22:45:11 | 显示全部楼层
wxfje 发表于 2014-9-9 22:07
楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点 ...

如果你方便的话,把自己的具体想法也贴出来吧,我们一起学习!

出0入0汤圆

发表于 2014-9-9 22:46:06 | 显示全部楼层
wangpengcheng 发表于 2014-9-9 22:37
同一个进程的lock与unlock倒是用到过,跟开关中断是一个道理!但互斥量的两态性还真没听说过,愿闻其详? ...

互斥量值只能为0/1,就是对应lock与unlock这两个状态。我开了另一个帖子:【交流学习】理解互斥量和信号量   欢迎拍砖,别打脸,哈哈!
http://www.amobbs.com/thread-5595285-1-1.html
因为我看了你的帖子后我觉的没有写出互斥量的特点,任意定义一个变量都可以做到你所说的互斥量的功能。

出0入0汤圆

发表于 2014-9-9 22:49:23 | 显示全部楼层
wxfje 发表于 2014-9-9 22:07
楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点 ...

感谢坛友顶我,不过楼主写的非常好了,要是我估计没这么大耐心。哈哈,懒了

出0入0汤圆

发表于 2014-9-9 23:18:12 来自手机 | 显示全部楼层
比喻不错      

出0入0汤圆

发表于 2014-9-9 23:39:04 来自手机 | 显示全部楼层
你这个是二值信号量,哪里体现互斥了

出0入0汤圆

发表于 2014-9-10 08:22:43 来自手机 | 显示全部楼层
ludikn 发表于 2014-9-9 23:39 你这个是二值信号量,哪里体现互斥了

楼主没有重点拎出来讲,不过应用的时候用到了互斥量的特性。

出0入0汤圆

发表于 2014-9-10 08:37:24 | 显示全部楼层
互斥量有优先级继承,解决了优先级翻转的问题

出0入0汤圆

 楼主| 发表于 2014-9-10 10:34:00 来自手机 | 显示全部楼层
ludikn 发表于 2014-9-9 23:39
你这个是二值信号量,哪里体现互斥了

能说说你理解的互斥量是什么样子的吗?

出0入0汤圆

 楼主| 发表于 2014-9-10 10:35:43 来自手机 | 显示全部楼层
0flame0 发表于 2014-9-10 08:37
互斥量有优先级继承,解决了优先级翻转的问题

能举个例子吗?

出0入0汤圆

发表于 2014-9-10 11:40:14 | 显示全部楼层

  有优先级依次降低的三个线程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之前运行。

出0入4汤圆

发表于 2014-9-10 11:59:21 | 显示全部楼层
很正式的名词解说往往费力不讨好,能跟恰当的比喻联系起来就事半功倍了。
还是喜欢比喻,能让人理解透彻,谢谢楼主和zulu

出0入0汤圆

 楼主| 发表于 2014-9-10 15:30:18 | 显示全部楼层
0flame0 发表于 2014-9-10 11:40
有优先级依次降低的三个线程A、B、C,假设A,B挂起,C正在运行,此时C开始使用共享资源。此时A转为就绪 ...

我感觉这个过程好是系统在做的吧?不用我们操心,是这样吗?

出0入0汤圆

发表于 2014-9-10 15:33:02 | 显示全部楼层
楼主真是个好老师~~

出0入0汤圆

发表于 2014-9-10 15:42:53 | 显示全部楼层
知道互斥量 是干嘛的了, 实际项目中还真没想好如何用。貌似还没遇到有冲突的东西。

楼主举例很形象。

出0入0汤圆

 楼主| 发表于 2014-9-10 16:05:14 | 显示全部楼层
street 发表于 2014-9-10 15:42
知道互斥量 是干嘛的了, 实际项目中还真没想好如何用。貌似还没遇到有冲突的东西。

楼主举例很形象。 ...

其实我就是感觉在任务中使用共同的资源,而且在使用过程中任务可能会释放CPU的时候,就必须用!

出0入0汤圆

发表于 2014-9-10 16:16:36 | 显示全部楼层
学习了,比喻很恰当,浅显易懂,感谢分享。

出0入0汤圆

发表于 2014-9-10 16:54:05 | 显示全部楼层
好东西啊学习

出0入0汤圆

发表于 2014-9-10 16:55:32 | 显示全部楼层
wangpengcheng 发表于 2014-9-10 16:05
其实我就是感觉在任务中使用共同的资源,而且在使用过程中任务可能会释放CPU的时候,就必须用! ...

如果我 有一个AD 芯片 有两个任务 需要获取AD的数据,但是AD每1S才能完成一次转换。

这样的话用互斥量 我感觉不妥。

有什么其他好的方法没有?

出0入0汤圆

发表于 2014-9-10 16:59:55 | 显示全部楼层
wangpengcheng 发表于 2014-9-10 15:30
我感觉这个过程好是系统在做的吧?不用我们操心,是这样吗?

对,不过也可以写个例子看看具体结果

出0入0汤圆

发表于 2014-9-10 17:03:09 | 显示全部楼层
楼主厉害,

出0入0汤圆

发表于 2014-9-10 17:12:18 | 显示全部楼层
很有用,MARK。

出0入0汤圆

发表于 2014-9-10 17:28:37 | 显示全部楼层
讲的不错.....很容易让人理解...

出0入0汤圆

 楼主| 发表于 2014-9-10 18:08:57 | 显示全部楼层
street 发表于 2014-9-10 16:55
如果我 有一个AD 芯片 有两个任务 需要获取AD的数据,但是AD每1S才能完成一次转换。

这样的话用互斥量  ...

你这个不需要用互斥量啊,因为任务在读AD芯片的时候不会让出CPU的,它不会说我发一个脉冲,然后等200MS,呵呵!你这个可以不用任务东西,直接读取就可以了,如果真要做,把AD做成驱动就行,意思就是有open\close\read\write\ioctl几个函数把AD功能包起来!

出0入0汤圆

 楼主| 发表于 2014-9-10 18:10:39 | 显示全部楼层
0flame0 发表于 2014-9-10 16:59
对,不过也可以写个例子看看具体结果

没必要动那个脑子了,呵呵,入门级的简单点就行!像那些东西入门后自己研究

出0入0汤圆

发表于 2014-9-10 19:11:56 | 显示全部楼层
学习了,赞一项下。

出0入0汤圆

发表于 2014-9-10 21:37:35 | 显示全部楼层
wangpengcheng 发表于 2014-9-9 22:45
如果你方便的话,把自己的具体想法也贴出来吧,我们一起学习!

迟了,那位兄弟已经发了

出0入0汤圆

发表于 2014-9-11 08:51:27 | 显示全部楼层
wangpengcheng 发表于 2014-9-10 18:10
没必要动那个脑子了,呵呵,入门级的简单点就行!像那些东西入门后自己研究 ...

其实你给一个用法就够了,  多搞些例程,  使用按键,  LED , 串口,这三样基本上能把MQX的大部分功能实现了;  
你一上来讲原理是没用的,这个东西是必须在实践中出真知,哪怕是理论上懂了,真用起来,依然是手忙脚乱,所以一开始直接给例程,跑范例;
PS : 原来开始搞OS的时候,我看互斥量,然后看咋用,咋弄,原理,都明明白白的,可真用起来,不晓得咋用了,直到某年某日,用多了,突然醒梧,这尼玛的三个字就表明了它的意图啊,"互斥"太精僻了,那为什么之前明明也是叫互斥量,可就是不明白呢?

出0入0汤圆

发表于 2014-10-6 17:39:22 | 显示全部楼层
生动,顶起来,楼主好样的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 22:58

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表