VxWorks信号量分析


Wind内核中有二进制信号量、计数信号量和互斥信号量三种类型,为了是运用程序具有可移植性,还提供了POSIX(可移植操作系统接口)信号量 。在VxWorks中,信号量是实现任务同步的主要手段,也是解决任务同步的最佳选择。

关于互斥的实现:

使用二进制信号量可以很方便的实现互斥,互斥是指多任务在访问临界资源时具有排他性。为了使多个任务互斥访问临界资源,只需要为该资源设置一个信号量,相当于一个令牌,那个任务拿到令牌即有权使用该资源。把信号量设置为可用,然后把需要的资源 的任务的临界代码 置于semTake()和semGive()之间即可。

注明:
1、互斥中的信号量与任务优先级的关系:任务的调度还是按照任务优先级进行,但是在使用临界资源的时候只有一个任务获得信号量,也就是说还是按照任务优先级获得信号量从而访问资源。只是当前使用资源的任务释放信号量semGive(),其它任务按照优先级获得信号量。

2、信号量属性中的参数为:SEM_Q_PRIORITY。而且在创建信号量的时候必须把信号量置为满SEM_FULL。即信号量可用。

基本实现互斥模型:

 1  SEM_ID semMutex;
 2 
 3  semMutex  =  semBCreate(SEM_Q_PRIORITY, SEM_FULL);
 4 
 5  task( void )
 6  {
 7 
 8        semTake(semMutex, WAIT_FOREVER); // 得到信号量,即相当于得到使用资源的令牌
 9 
10          // 临界区,某一个时刻只能由一个任务 访问
11 
12         semGive(semMutex);
13 
14  }


关于任务同步的实现

同步即任务按照一定的顺序先后执行,为了实现任务A和B同步,只需要让任务A和B共享一个信号量,并设置初始值为空,即不可用,将semGive()置于任务A之后,而在任务B之前插入semTake()即可。

说明:
1、还是讨论和优先级的关系。由于信号量初始化为空,不可用,所以可能使得优先级反转,即高优先级任务B在等待低优先级任务A释放信号量。只有执行了信号量释放语句semGive()后任务B得到信号量才能执行。

2、属性参数的设置为SEM_Q_FIFO,SEM_EMPTY;

实现模型参考

 1  SEM_ID semSync;
 2 
 3  semSync  =  semBCreate(SEM_Q_FIFO, SEM_EMPTY);
 4 
 5  taskA( void )
 6  {
 7      
 8 
 9      semGive(semSync);       // 信号量释放,有效
10  }
11  taskB( void )
12  {
13 
14      semTake(semSync, WAIT_FOREVER);    // 等待信号量
15 
16       .
17  }

使用信号量注意事项:

1、用途不同,信号量属性和初始值不同。

2、互斥访问资源时,semTake()和semGive()必须成对出现,且先后顺序不能颠倒。

3、避免删除那些其它任务正在请求的信号量。

应用:

1、确保任务优先级不反转

 1  SEM_ID semFs;
 2  SEM_ID semFss;
 3  SEM_ID semFex;
 4 
 5  semFs  =  semBCreate(SEM_Q_FIFO,  SEM_EMPTY);
 6  semFss  =  semBCreate(SEM_Q_FIFO, SEM_EMPTY);
 7  semFex  =  semBCreate(SEM_Q_FIFO, SEM_EMPTY);
 8 
 9  void  t_imaGet( void )
10  {
11      printf( " a    " );
12      semGive(semFs);    // 释放信号量
13  }
14 
15  void  t_imaJud( void )
16  {
17      semTake(semFs, WAIT_FOREVER); // 确保优先级不反转
18 
19      printf( " jj  " );
20      semGive(semFss);
21  }
22 
23  void  t_imaPro( void )
24  {
25      semTake(semFss, WAIT_FOREVER);
26      printf( " rr " );
27      semGive(semFex);
28  }
29 
30  void  t_imaExc( void )
31  {
32      semTake(semFex, WAIT_FOREVER);
33      printf( " Y " );
34  }
35 
36  void  start( void )
37  {
38       int  tGetId, tJudId, tProId, tExcId;
39      tGetId  =  taskSpawn( " tPget " 200 0 1000 ,(FUNCPTR)t_imaGet,  1 0 0 0 0 0 0 0 0 0 );
40      tJudId  =  taskSpawn( " tPjud " , 201 , 0 , 1000 ,(FUNCPTR)t_imaJud, 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ); 
41      tProId  =  taskSpawn( " tPpro " , 202 , 0 , 1000 ,(FUNCPTR)t_imaPro, 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ); 
42      tExcId  =  taskSpawn( " tPexc " , 203 , 0 , 1000 ,(FUNCPTR)t_imaExc, 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 );
43 
44  }
以上例子虽然定了各个任务的优先级,但是加上信号量可以 实现同步,而且防止优先级反转的出现。

你可能感兴趣的:(信号量)