您的位置:首页 > 运维架构 > Nginx

nginx源码分析1———进程间的通信机制二(自旋锁)

2015-07-23 18:53 811 查看

自旋锁的相关介绍

自旋锁的释义

自旋锁与其他的锁最大的区别就是自旋锁不会引起调用者睡眠(非睡眠锁),也就是始终是可执行状态。如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里,看是否该自旋锁的保持者已经释放了锁。

自旋锁的适用场景

当锁的使用时间很短的时候,就可以采用自旋锁,这样开销很小。如果时间很长,锁一直自旋,又不能调度其他的程序,cpu资源将被大量占用,这样就不是很合适。对于长时间的锁,应该使用让它休眠的锁,而不应该是自旋。

自旋锁无论是单核还是多核,都将是有效的,一直处于可执行态,是可以少一些状态的转换,如果切换到睡眠态,还得从休眠态转化到就绪态,然后才能供cpu调度(如果不是很清楚,就得多了解操作系统处理器调度相关的知识)。

nginx的相关实现

void
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
{
//在有原子变量支持的情况下
#if (NGX_HAVE_ATOMIC_OPS)
ngx_uint_t  i, n;
for ( ;; ) {
//先判断一次锁,然后尝试获取锁(compare and set)
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
//如果成功获取到就直接return。
return;
}
//在cpu大于1的情况下才会去自旋
if (ngx_ncpu > 1) {
//仔细看这个双层for循环随着n的增大nginx_cpu_pause执行的间隔就越大。
for (n = 1; n < spin; n <<= 1) {
for (i = 0; i < n; i++) {
//架构体系中专门为了自旋锁而提供的指令,它会告诉CPU现在处于自旋锁等待状态,通常一个CPU会将自己置于节能状态,降低功耗。但是当前进程并没有让出正在使用的处理器。
ngx_cpu_pause();
}
//尝试去获取锁,尝试获取锁的次数并不多,是spin的一个对数关系,而且时间间隔会越来越大。
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
return;
}
}
}
//在一个for循环之内usleep(1) 暂时让出处理器
ngx_sched_yield();
}
#else
#if (NGX_THREADS)
#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
#endif
#endif
}


可以看到nginx充分利用了多核和单核的场景,里面的双层for循环其实也是博大精深,其余的细节也格外精辟。自旋锁在短时间锁上面是非常高效和有用的。细致的你,应该会发现在ngx_shmtx_lock方法里面,也采用了自旋锁和信号量一起的方式去实现的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: