1. 程式人生 > >關於ngx_trylock_accept_mutex的一些解釋

關於ngx_trylock_accept_mutex的一些解釋

關於nginx裡面accept互斥鎖的處理,群裡討論了很多次,很多人都提出了各種問題,比如問到:在ngx_process_events_and_timers中,為什麼在釋放ngx_accept_mutex之後,不把ngx_accept_mutex_held清零?

 
  1. if (ngx_accept_mutex_held) {

  2. ngx_shmtx_unlock(&ngx_accept_mutex);

  3. /* 有人說應該加上ngx_accept_mutex_held = 0; */

  4. }

這裡我們好好分析一下ngx_trylock_accept_mutex函式,它就能給我們答案:

 
  1. ngx_int_t

  2. ngx_trylock_accept_mutex(ngx_cycle_t *cycle)

  3. {

  4. if (ngx_shmtx_trylock(&ngx_accept_mutex)) {

  5.  
  6. if (ngx_enable_accept_events(cycle) == NGX_ERROR) {

  7. ngx_shmtx_unlock(&ngx_accept_mutex);

  8. return NGX_ERROR;

  9. }

  10.  
  11. ngx_accept_mutex_held = 1;

  12.  
  13. return NGX_OK;

  14. }

  15.  
  16. if (ngx_accept_mutex_held) {

  17. if (ngx_disable_accept_events(cycle) == NGX_ERROR) {

  18. return NGX_ERROR;

  19. }

  20.  
  21. ngx_accept_mutex_held = 0;

  22. }

  23.  
  24. return NGX_OK;

  25. }

對照這個函式,我們假想一個情景,若此時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。

 
  1. if (ngx_accept_mutex_held) {

  2. ngx_shmtx_unlock(&ngx_accept_mutex);

  3. }

接下來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)。

 
  1. if (ngx_accept_mutex_held) {

  2. if (ngx_disable_accept_events(cycle) == NGX_ERROR) {

  3. return NGX_ERROR;

  4. }

  5. ngx_accept_mutex_held = 0;

  6. }

說到這裡大家別混淆了,nginx的epoll是每個程序私有了,可能在有些系統的設計裡,epoll是執行緒(或者程序)共享的。

--------------------- 本文來自 aweth0me 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/brainkick/article/details/9081017?utm_source=copy