|

楼主 |
发表于 2004-11-11 09:50:58
|
显示全部楼层
最初由 kj501 发表
我觉得你只看到了问题的一个方面:
如果是同一进程的不同线程之间的同步,用户态的线程完全可以在用户态实现自己的同步机制,不需要陷入内核态去使用内核提供的信号灯,这种情况在实际应用中是很多的,效率也是很高的;如果是分别属于不同进程的线程之间的同步,这种情况下就需要进程的同步,自然要使用内核的信号灯。多了从用户态到内核态切换的开销,自然效率就要下降了。
确实如此,在《WINDOWS核心编程》作者就提到了这个问题。
能用USER MODE同步方式就尽量用USER MODE同步方式。
凡是同步用到了KERNEL MODE和USER MODE之间切换,至少耗费几千个CPU周期。
在WINDOWS下,Interlocked系列函数,都是用来在USER MODE里对某个数值进行原子操作增加或者减少的函数。
在WINDOWS下,有一个临界区CriticalSection和LINUX下的pthread_mutex_t使用方法是一样的,作用也一样。
在同步方式中,凡是可以让线程或者进程挂起等待的同步方式,肯定必须在USER MODE和KERNEL MODE之间切换。信号灯大多数场合效率都比pthread_mutex_t低,因为凡是信号灯,就必须在USER MODE和KERNEL MODE之间切换。而pthread_mutex_t,每次调用lock的时候,如果此时没有别的线程在使用pthread_mutex_t保护的资源,那么他就不需要挂起,也就无须切换到KERNEL MODE里。只有在别的线程已经lock了,再次想去lock的线程才会切换到KERNEL MODE里去挂起等待。
WINDOWS里面,为了提高同步效率,在对临界区资源的使用中,甚至还提供了一个函数:EnterCriticalSectionAndSpin。可以指定一个int参数,用来指明,当某个线程想去LOCK的时候,如果有别的线程已经先LOCK了,那么这个线程不直接进入内核状态挂起,而是轮训int参数指定的次数,如果在轮训中别的线程UNLOCK了,这个线程就避免了一次KERNEL MODE的切换。只有在轮训完后,别的线程还没UNLOCK,才会切换到内核模式挂起。由此可以见,USER MODE和KERNEL MODE的切换效率损失是很大的。 WINDOWS系统本身用的对堆栈保护的轮训次数是4000次。
虽然是不同的操作系统,但是我想有很大的参考价值。 |
|