wangpengcheng 发表于 2014-9-9 13:28:33

原创:我跟你一起学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:18

活学活用的好榜样,赞一个!

wangpengcheng 发表于 2014-9-9 13:44:01

wycox 发表于 2014-9-9 13:40
活学活用的好榜样,赞一个!

谢谢啊!呵呵!

sdlibin007 发表于 2014-9-9 13:45:12

楼主这个生动的亲身经历讲解程序,简直神了!1

wangpengcheng 发表于 2014-9-9 13:48:14

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

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

sdlibin007 发表于 2014-9-9 13:52:10

wangpengcheng 发表于 2014-9-9 13:48
只是觉得这个例子用来解释互斥量比较形像,呵呵!

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

32MCU 发表于 2014-9-9 13:57:39

跟着楼主学习,这样学的更快。

wangpengcheng 发表于 2014-9-9 13:59:10

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

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

wangpengcheng 发表于 2014-9-9 13:59:51

本帖最后由 wangpengcheng 于 2014-9-9 14:01 编辑

32MCU 发表于 2014-9-9 13:57
跟着楼主学习,这样学的更快。

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

步之道 发表于 2014-9-9 14:02:22

看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。

rockyyangyang 发表于 2014-9-9 14:04:54

你真调皮,举得例子已经很明白的讲了什么是互斥量,非常生动形象。

wangpengcheng 发表于 2014-9-9 14:06:13

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

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

wangpengcheng 发表于 2014-9-9 14:06:46

步之道 发表于 2014-9-9 14:02
看到这,我就火速来学习了,刚粗看了一遍,稍后再细看一遍。

有问题可以讨论哈

步之道 发表于 2014-9-9 14:16:56

wangpengcheng 发表于 2014-9-9 14:06
有问题可以讨论哈

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

bestlong22 发表于 2014-9-9 14:17:32

赞,让人能够清晰互斥量的基本意思

wangpengcheng 发表于 2014-9-9 14:22:29

步之道 发表于 2014-9-9 14:16
在公司不方便细看,晚上回去看,有不明白的向楼主请教,哈哈,千万别嫌烦。 ...

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

wangpengcheng 发表于 2014-9-9 14:22:51

bestlong22 发表于 2014-9-9 14:17
赞,让人能够清晰互斥量的基本意思

谢谢点赞

fengyunyu 发表于 2014-9-9 17:00:34

LZ,你这个讲解真是通俗易懂,“通透”。

qwert1213131 发表于 2014-9-9 17:18:27

旅客A得虚脱了;
楼主讲的很不错。等待下一讲,

qs6361036 发表于 2014-9-9 17:26:12

呵呵   楼主解释的挺有意思

lzl000 发表于 2014-9-9 17:31:45

用例讲解,楼主有当老师的天分啊

wangpengcheng 发表于 2014-9-9 17:47:09

qwert1213131 发表于 2014-9-9 17:18
旅客A得虚脱了;
楼主讲的很不错。等待下一讲,

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

wangpengcheng 发表于 2014-9-9 17:47:43

lzl000 发表于 2014-9-9 17:31
用例讲解,楼主有当老师的天分啊

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

yzb1019 发表于 2014-9-9 20:39:57

楼主,你可以出一本书了。任哲板的ucos讲的也不过你这个水平。很生动形象,而且北航的一本书也很不错

caesarsong 发表于 2014-9-9 20:54:45

好东西啊 一定要顶一个

步之道 发表于 2014-9-9 21:18:52

楼主,没有说到互斥量的两特性:1、同一个进程lock和unlock。2、互斥量的两态性。

lcl 发表于 2014-9-9 21:24:30

楼主真乃神人也~

wuguoyan 发表于 2014-9-9 21:24:32

楼主的“跟我学MQX”系列教程不错,通俗易懂,这个也同样适用于其他的RTOS。

步之道 发表于 2014-9-9 21:25:42

我觉得这两点应该着重点出来,因为很容易和上一次讲的信号量混淆。从而导致互斥量的特点不够鲜明。

关于以后 发表于 2014-9-9 21:26:51

楼主真是善于思考。

qinshiysb 发表于 2014-9-9 21:42:12

楼主的讲解有风趣又有内涵,挺期待哈!楼楼接下来的更新都会看的

wxfje 发表于 2014-9-9 22:07:13

楼主讲的非常具体生动,很形象很透彻,对于不懂这块的来说是非常好的
但是如26楼所说,互斥量的特性没有点明

wangpengcheng 发表于 2014-9-9 22:37:27

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

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

nishuizhou 发表于 2014-9-9 22:39:46

能讲到别人听了很懂了,说明你也是大师

wangpengcheng 发表于 2014-9-9 22:41:00

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

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

wangpengcheng 发表于 2014-9-9 22:41:50

nishuizhou 发表于 2014-9-9 22:39
能讲到别人听了很懂了,说明你也是大师

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

wangpengcheng 发表于 2014-9-9 22:43:24

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

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

wangpengcheng 发表于 2014-9-9 22:45:11

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

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

步之道 发表于 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
因为我看了你的帖子后我觉的没有写出互斥量的特点,任意定义一个变量都可以做到你所说的互斥量的功能。

步之道 发表于 2014-9-9 22:49:23

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

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

wang110 发表于 2014-9-9 23:18:12

比喻不错      

ludikn 发表于 2014-9-9 23:39:04

你这个是二值信号量,哪里体现互斥了

步之道 发表于 2014-9-10 08:22:43

ludikn 发表于 2014-9-9 23:39 你这个是二值信号量,哪里体现互斥了

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

0flame0 发表于 2014-9-10 08:37:24

互斥量有优先级继承,解决了优先级翻转的问题

wangpengcheng 发表于 2014-9-10 10:34:00

ludikn 发表于 2014-9-9 23:39
你这个是二值信号量,哪里体现互斥了

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

wangpengcheng 发表于 2014-9-10 10:35:43

0flame0 发表于 2014-9-10 08:37
互斥量有优先级继承,解决了优先级翻转的问题

能举个例子吗?

0flame0 发表于 2014-9-10 11:40:14

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之前运行。

sunliezhi 发表于 2014-9-10 11:59:21

很正式的名词解说往往费力不讨好,能跟恰当的比喻联系起来就事半功倍了。
还是喜欢比喻,能让人理解透彻,谢谢楼主和zulu

wangpengcheng 发表于 2014-9-10 15:30:18

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

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

5dk 发表于 2014-9-10 15:33:02

楼主真是个好老师~~

street 发表于 2014-9-10 15:42:53

知道互斥量 是干嘛的了, 实际项目中还真没想好如何用。貌似还没遇到有冲突的东西。

楼主举例很形象。

wangpengcheng 发表于 2014-9-10 16:05:14

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

楼主举例很形象。 ...

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

浪里白条 发表于 2014-9-10 16:16:36

学习了,比喻很恰当,浅显易懂,感谢分享。

cqsgcqsg 发表于 2014-9-10 16:54:05

好东西啊学习

street 发表于 2014-9-10 16:55:32

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

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

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

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

0flame0 发表于 2014-9-10 16:59:55

wangpengcheng 发表于 2014-9-10 15:30
我感觉这个过程好是系统在做的吧?不用我们操心,是这样吗?

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

pyroseeking 发表于 2014-9-10 17:03:09

楼主厉害,

apad 发表于 2014-9-10 17:12:18

很有用,MARK。

RainKing 发表于 2014-9-10 17:28:37

讲的不错.....很容易让人理解...

wangpengcheng 发表于 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功能包起来!

wangpengcheng 发表于 2014-9-10 18:10:39

0flame0 发表于 2014-9-10 16:59
对,不过也可以写个例子看看具体结果

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

klxx68 发表于 2014-9-10 19:11:56

学习了,赞一项下。

wxfje 发表于 2014-9-10 21:37:35

wangpengcheng 发表于 2014-9-9 22:45
如果你方便的话,把自己的具体想法也贴出来吧,我们一起学习!

迟了,那位兄弟已经发了{:mad:}

kinsno 发表于 2014-9-11 08:51:27

wangpengcheng 发表于 2014-9-10 18:10
没必要动那个脑子了,呵呵,入门级的简单点就行!像那些东西入门后自己研究 ...

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

hanjiang 发表于 2014-10-6 17:39:22

生动,顶起来,楼主好样的
页: [1]
查看完整版本: 原创:我跟你一起学MQX(三):互斥量