东莞整合网站建设公司,wordpress 显示热度,网站定制站,健康咨询类网站模板我们一般认为nginx是一个多进程单线程的应用服务#xff0c;虽然nginx在一个worker进程内是没有数据竞争问题的#xff08;因为是单线程#xff09;#xff0c;但是不免nginx在多个进程间还有一些需要共享的数据#xff0c;譬如ngx_http_upstream_zone_module模块将peers数… 我们一般认为nginx是一个多进程单线程的应用服务虽然nginx在一个worker进程内是没有数据竞争问题的因为是单线程但是不免nginx在多个进程间还有一些需要共享的数据譬如ngx_http_upstream_zone_module模块将peers数据放在了共享内存中供多个worker进程来使用又譬如ngx_http_limit_conn_module模块将并发连接数限制也放在了共享内存中诸如此类的自然会涉及到共享内存访问的互斥锁的问题本文对nginx实现的互斥锁进行分析通过分析学习nginx的实现代码以便将来可以应用到自己的日常应用程序中去。 nginx的读写锁实现逻辑是通过自旋锁来实现的。 nginx一共实现了以下几个api函数
void ngx_rwlock_wlock(ngx_atomic_t *lock);
void ngx_rwlock_rlock(ngx_atomic_t *lock);
void ngx_rwlock_unlock(ngx_atomic_t *lock);
void ngx_rwlock_downgrade(ngx_atomic_t *lock);ngx_rwlock_wlock用来加写锁ngx_rwlock_rlock用来加读锁ngx_rwlock_unlock用来对加的锁进行释放ngx_rwlock_downgrade对写锁进行降级为读锁。 锁变量是ngx_atomic_t类型对应的就是一个unsigned long的类型。
以下是ngx_rwlock_wlock的实现代码
void
ngx_rwlock_wlock(ngx_atomic_t *lock)
{ngx_uint_t i, n;for ( ;; ) {/* 如果*lock的值是0表示现在没有加任何读写锁ngx_atomic_cmp_set比较如果是lock是0,则将其设置为NGX_RWLOCK_WLOCK表示加锁成功可以返回了*/if (*lock 0 ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {return;}if (ngx_ncpu 1) {/* 对于多cpu的情况需要进行自旋加锁检测 */for (n 1; n NGX_RWLOCK_SPIN; n 1) {for (i 0; i n; i) {ngx_cpu_pause();}if (*lock 0 ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)){return;}}}/* 通知os将自己切出调度到其他进程 */ngx_sched_yield();}
}以下是ngx_rwlock_rlock的实现代码 void
ngx_rwlock_rlock(ngx_atomic_t *lock)
{ngx_uint_t i, n;ngx_atomic_uint_t readers;for ( ;; ) {readers *lock;/* 如果*lock的值不是NGX_RWLOCK_WLOCK表示现在没有加写锁则可以尝试获取读锁ngx_atomic_cmp_set比较如果是lock和之前保存的readers一致,则将其设置为readers1,表示加锁成功可以返回了*/if (readers ! NGX_RWLOCK_WLOCK ngx_atomic_cmp_set(lock, readers, readers 1)){return;}if (ngx_ncpu 1) {/* 对于多cpu的情况需要进行自旋加锁检测 */for (n 1; n NGX_RWLOCK_SPIN; n 1) {for (i 0; i n; i) {ngx_cpu_pause();}readers *lock;if (readers ! NGX_RWLOCK_WLOCK ngx_atomic_cmp_set(lock, readers, readers 1)){return;}}}/* 通知os将自己切出调度到其他进程 */ngx_sched_yield();}
}以下是ngx_rwlock_unlock的实现代码
void
ngx_rwlock_unlock(ngx_atomic_t *lock)
{if (*lock NGX_RWLOCK_WLOCK) {/* 如果是写锁定了那么将*lock置为0,表示没有加任何锁了*/(void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0);} else {/*如果当前是读锁定了那么只是将*lock-1表示少了一个读者 */(void) ngx_atomic_fetch_add(lock, -1);}
}
以下是ngx_rwlock_downgrade的实现代码
void
ngx_rwlock_downgrade(ngx_atomic_t *lock)
{/* 如果当前是加上了写锁的因为肯定没有读者将自己变为读者所以只有1个读者因此将*lock设置为1*/if (*lock NGX_RWLOCK_WLOCK) {*lock 1;}
}