2009-11-22 34 views
17

如果您解鎖已經解鎖的互斥鎖,是不安全的,安全的還是未定義的行爲?如果你解鎖一個已經解鎖的互斥體,那麼這個行爲是不確定的?

該問題的目的與下面的代碼有關,我不知道在if區塊內還是在if區塊之外解鎖互斥鎖會更好。

// This chunk of code makes dual locking semi-autonomous. 
    int c_lckd = 0, q_lckd = 0; 
    if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; 
    if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; 
    if (q_lckd && !c_lckd) { QUEUE_UNLOCK; q_lckd = 0; } 
    else if (c_lckd && !q_lckd) { CRUNCH_UNLOCK; c_lckd = 0; } 

    if (c_lckd && q_lckd) { 
     printf("cr = %d, max = %d, cnt = %d\n", 
     crunching, max_crunching, queue_count(conn_queue)); 
     if (crunching < max_crunching && queue_count(conn_queue)) { 
     pthread_t tid = 
      pthread_create(
      &tid, 
      NULL, 
      crunch_conn, 
      (void *)queue_dequeue(conn_queue) 
     ); 
     crunching++; 
     } 
     CRUNCH_UNLOCK QUEUE_UNLOCK 
    } 

感謝, Chenz

回答

17

對於pthreads,它將導致未定義的行爲。從手冊頁pthread_mutex_unlock

調用調用pthread_mutex_unlock()的調用線程未持有會導致不確定的行爲互斥。

其他mutexes將有自己的behviour。正如其他人所說的,最好是閱讀你正在使用的互斥體的手冊。

+0

結果取決於您已提供鏈接的手冊頁的互斥類型。根據頁面的行爲是'未定義'或返回錯誤。 – 2015-12-09 20:25:28

1

你不必這樣做的。試試這個:

// This chunk of code makes dual locking semi-autonomous. 
int c_lckd = 0, q_lckd = 0; 
if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; 
if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; 

if (c_lckd && q_lckd) { 
    printf("cr = %d, max = %d, cnt = %d\n", 
    crunching, max_crunching, queue_count(conn_queue)); 
    if (crunching < max_crunching && queue_count(conn_queue)) { 
    pthread_t tid = 
     pthread_create(
     &tid, 
     NULL, 
     crunch_conn, 
     (void *)queue_dequeue(conn_queue) 
    ); 
    crunching++; 
    } 

} 

if (q_lckd) { QUEUE_UNLOCK; q_lckd = 0; } 
if (c_lckd) { CRUNCH_UNLOCK; c_lckd = 0; } 

這是一個更容易遵循,並沒有冒險試圖解鎖一個解鎖的互斥體。

+0

謝謝!,這確實清理了一下。儘管如果有人知道POSIX標準中是否明確聲明瞭「解鎖和解鎖」模式,我仍然會感興趣。 – 2009-11-22 14:09:06

+0

是的,就像我編輯我的代碼一樣。抱歉! – 2009-11-22 17:38:58

+0

即使它是在POSIX中指定的,我也會避免這樣做 - 我的經驗使我遠離這樣一個奇怪的角落 - 即使它被指定了,我已經被燒得太多次了,而且沒有被遵守圖書館很舒服地嘗試它。 – 2009-11-22 17:42:50

2

一般來說,對於這樣的問題,文檔是最好的信息來源。不同的互斥體行爲可能會有所不同,或者在單個互斥體上可能存在選項,導致其行爲不同(例如,在單個線程上遞歸獲取互斥鎖的情況下)。

7

正如Glen指出的那樣,如果您嘗試使用解鎖互斥鎖unlock,您會遇到未定義的行爲 - 請勿嘗試。除非調用未定義的行爲,否則調試線程已足夠困難。

更重要的是,編碼風格是有點不尋常 - 因爲你不會,除非你獲得兩個鎖做任何事情,相應代碼:

if (pthread_mutex_trylock(&crunch_mutex) == 0) 
{ 
    if (pthread_mutex_trylock(&queue_mutex) == 0) 
    { 
     printf("cr = %d, max = %d, cnt = %d\n", 
       crunching, max_crunching, queue_count(conn_queue)); 
     if (crunching < max_crunching && queue_count(conn_queue)) 
     { 
      pthread_t tid; 
      int rc = pthread_create(&tid, NULL, 
           crunch_conn, (void *)queue_dequeue(conn_queue)); 
      if (rc != 0) 
      { 
       // Error recovery 
       // Did you need what was returned by queue_dequeue() 
       // to requeue it, perhaps? 
      } 
      else 
      { 
       crunching++; 
       // Do something with tid here? 
      } 
     } 
     QUEUE_UNLOCK; 
    } 
    CRUNCH_UNLOCK; 
} 

這就避免了「豈是」變量;它也立即清楚地表明,只要解鎖宏執行了預期的操作(並且沒有任何雜散的異常或setjmp),鎖定的互斥鎖就會解鎖。它還避免了在緊急互斥鎖不可用時鎖定隊列互斥體的浪費 - 但與增加的清晰度相比,這是一個小問題。

0

只有在同一個線程中同一個互斥鎖被鎖定的情況下,才應該在線程中完成互斥鎖解鎖。所有其他案例都是根據手冊頁未定義的。

如果互斥鎖類型爲PTHREAD_MUTEX_DEFAULT,試圖遞歸 鎖定在不確定的行爲互斥的結果。試圖解鎖 該互斥量如果未被調用線程鎖定,則會導致 未定義的行爲。試圖解鎖互斥鎖,如果它不是 鎖定導致未定義的行爲。

0

試試吧。這是代碼工作正確。

// Mutex is not busy 
if(pthread_mutex_trylock(&object->mtx) == 0) { 
    if(pthread_mutex_unlock(&object->mtx)!=0) { 
     perror("ERRN: pthread_mutex_unlock:"); 
    } 
} 
// Mutex is already busy 
else { 
    if(pthread_mutex_unlock(&object->mtx)!=0) { 
     perror("ERRN: pthread_mutex_unlock:"); 
    } 
} 

// 在這一點上 - 我們正確地解鎖了互斥鎖。

if(pthread_mutex_destroy(&object->mtx) != 0) { 
    perror("ERRN: pthread_mutex_destroy:"); 
} 
相關問題