2014-02-24 109 views
3

我已经在vxWorks平台上运行一个示例C++程序来测试互斥量和二进制信号量之间的时间差异。下面的程序是原型计时开销二进制信号量与互斥量

SEM ID semMutex; 
UINT ITER = 10000; 
taskIdOne = TASKSPAWN("t1",TASK_PRIORITY_2,0,8192,0,(FUNCPTR)myMutexMethod,0,0); 
taskIdTwo = TASKSPAWN("t2",TASK_PRIORITY_2,0,8192,0,(FUNCPTR)myMutexMethod,0,0); 
void myMutexMethod(void) 
    { 
     int i; 
     VKI_PRINTF("I'm (%s)\n",TASKNAME(0)); 
     myMutexTimer.start(); 
     for (i=0; i < ITER; i++) 
     { 
      MUTEX_LOCK(semMutex,WAIT_FOREVER); 
      ++global;      
      MUTEX_UNLOCK(semMutex); 
     } 
     myMutexTimer.stop(); 
     myMutexTimer.show(); 
    } 

在上面的程序中有一个争用(2任务试图获得互斥体)。我的计时器为上述程序打印了37.43毫秒。使用相同的原型,二进制信号程序只需要2.8 ms。这是可以理解的,因为二进制信号量是轻量级的,并没有像互斥体(优先级反转,所有权等)的许多功能。

但是,我删除了一个任务并运行上述程序(没有争用)。由于没有争用,任务t1只是获取互斥锁,执行临界区然后释放互斥锁。与二进制信号相同。
对于定时,互斥量我得到了3.35毫秒和二进制信号量4毫秒。

我很惊讶地看到互斥体在没有争用时比二进制信号量更快。
这是预期吗?或者我错过了什么?

任何帮助表示赞赏。 !

+0

我认为(但不确定)这种测量线程同步机制的方式不会给你正确的结果,因为定时器还会跟踪等待互斥锁的时间。这不仅取决于互斥体和信号量的实现,还取决于操作系统将时隙分配给程序的方式。这在每次运行时都可能会有所不同。你有多少次试过这个和多久? – Excelcius

+0

我已经跑了20次,结果一致。我在我的控制器的一个空闲内核上运行这个程序,以便这个任务不会受到当前内核中已经运行的任务的干扰。 –

+0

信号量通常不被认为是“轻量级”的。如果一个线程无法获得一个单元,那么它必须阻塞内核调用,就像一个互斥体一样。 –

回答

1

在这种情况下,互斥体可能会更快,因为相同的任务反复进行并且没有其他任务涉及。我的猜测是,互斥体代码正在采用快捷方式来启用递归互斥体调用(即同一个任务需要两次相同的互斥体)。即使你的代码在技术上并不是一个递归的互斥量,但代码可能使用相同的快捷方式,因为信号量所有者没有被其他任何采用信号量的任务覆盖。

换句话说,你做的事:

1) semTake(semMutex) 
2) ++global; 
3) semGive(semMutex) // sem owner flag is not changed 
4) sameTake(semMutex) // from same task as previous semTake 
... 

然后在第4步semTake看到的是SEM所有者==当前任务的ID(因为SEM业主在步骤1中设置并没有改变,以其他任何东西),所以它只是标记了信号量并迅速跳出。

当然这是一个猜测,快速查看源代码和某些vxworks shell断点可以证实这一点,这是我无法做到的,因为我无法再访问vxworks。

另外看一下关于递归使用互斥锁的一些文档的semMLib文档。

+0

克里斯,你真棒。非常好的解释。即使我相信同样的事情正在发生。它正在得到优化,因为semOwner每次都是一样的。谢啦 ! –