關於ngx_trylock_accept_mutex的一些解釋
關於nginx裡面accept互斥鎖的處理,群裡討論了很多次,很多人都提出了各種問題,比如問到:在ngx_process_events_and_timers中,為什麼在釋放ngx_accept_mutex之後,不把ngx_accept_mutex_held清零?
-
if (ngx_accept_mutex_held) {
-
ngx_shmtx_unlock(&ngx_accept_mutex);
-
/* 有人說應該加上ngx_accept_mutex_held = 0; */
-
}
這裡我們好好分析一下ngx_trylock_accept_mutex函式,它就能給我們答案:
-
ngx_int_t
-
ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
-
{
-
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
-
if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
-
ngx_shmtx_unlock(&ngx_accept_mutex);
-
return NGX_ERROR;
-
}
-
ngx_accept_mutex_held = 1;
-
return NGX_OK;
-
}
-
if (ngx_accept_mutex_held) {
-
if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
-
return NGX_ERROR;
-
}
-
ngx_accept_mutex_held = 0;
-
}
-
return NGX_OK;
-
}
對照這個函式,我們假想一個情景,若此時nginx有兩個worker,我們稱為A和B。當A執行這個函式,並在呼叫ngx_shmtx_trylock時成功,這時它將listen fd註冊到自己的epoll中(即ngx_enable_accept_events),然後ngx_accept_mutex_held被置1。注意哦,這裡ngx_enable_accept_events處理之後就將其置1是為了表達listen fd此時被A程序註冊到epoll中了。很顯然這個時候B程序由於獲取accept鎖失敗,自然就沒有權利accept了。當程序A在處理完accept之後,就會釋放accept鎖,讓B在下一輪競爭中能有機會獲取鎖來做accept。
-
if (ngx_accept_mutex_held) {
-
ngx_shmtx_unlock(&ngx_accept_mutex);
-
}
接下來B很爭氣,獲得了accept鎖,跟當年程序A一樣將listen fd加到epoll中,處理過程如出一轍。這個時候我們來看A程序,由於這次在跟B的較量中敗北,但是ngx_accept_mutex_held為true,表明之前曾經註冊過listen fd。別忘了失敗的代價就是要交出listen fd,皇帝的位置現在由B來做,王冠現在不屬於你了。由於此時只有B有權將listen fd註冊到自己的epoll中,其他的程序(ngx_accept_mutex_held為true的程序)就要將listen fd從自己的epoll中移除(即ngx_disable_accept_events)。
-
if (ngx_accept_mutex_held) {
-
if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
-
return NGX_ERROR;
-
}
-
ngx_accept_mutex_held = 0;
-
}
說到這裡大家別混淆了,nginx的epoll是每個程序私有了,可能在有些系統的設計裡,epoll是執行緒(或者程序)共享的。
--------------------- 本文來自 aweth0me 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/brainkick/article/details/9081017?utm_source=copy