2013-02-07 54 views
1
gcc 4.7.2 
c89 

你好使用互斥鎖,關鍵代碼

我只是想知道如何申請互斥鎖下面的代碼片段。

是否有任何規則應該遵循,因爲我不想鎖定,因爲這會阻止此函數中的其他線程。因爲這會讓事情減緩。

我用下面的CFLAGS編譯:

-Wall -Wextra -g -m32 -O2 -D_DEBUG -D_THREAD_SAFE -D_REENTRANT -D_LARGEFILE64_SOURCE 

代碼片斷

static void* APR_THREAD_FUNC timeout_duration(apr_thread_t *thd, void *data) 
{ 
apr_status_t rv = 0; 
channel_t *channel = NULL; 

/* 
    APPLY LOCK HERE 
*/ 
channel = (channel_t*)data; 

/* simulate some work */ 
apr_sleep(5000000); 

LOG_INFO("Channel id [ %d ] Channel name [ %s ] Delay time [ %d ]", 
     channel->id, 
     channel->name, 
     (apr_int32_t)channel->delay_time); 

/* 
    UNLOCK HERE 
*/ 

return NULL; 
} 

我通過通道作爲傳遞到輸入功能的數據。但是,這不僅僅是一個副本,所以我不需要擔心它?

+0

ptr!=副本數據的副本。 –

回答

2

的規則是:

1)鎖保護數據,而不是代碼。當數據受鎖保護時,訪問該數據的代碼必須獲取數據的鎖。

2)鎖應儘可能早地獲得並儘早釋放。這可以包括將工作從關鍵部分轉移到關鍵部分之外。

3)只讀(而不是修改)的數據不需要鎖。這包括諸如"Channel id [ %d ] ..."格式字符串(應被視爲常量)之類的內容。

4)只能由一個線程訪問的數據不需要鎖定。這包括諸如函數參數和局部變量之類的東西。 5)細粒度鎖定優於粗粒度鎖定。例如,不是讓一個大型數據結構具有一個鎖,通常可以將該大型數據結構拆分爲許多具有多個鎖的較小結構。

6)如果任何代碼一次需要多個鎖,則需要定義一個「鎖定順序」。例如,如果一個線程獲取鎖A然後鎖B,則執行一些工作然後釋放鎖;如果另一個線程獲取了鎖B,然後鎖定A,則執行一些工作然後釋放鎖;那麼你可能會死鎖(每個線程有一個鎖,但需要兩個繼續)。定義一個「鎖定順序」(例如說在鎖B之前必須獲取鎖A)可以防止這種錯誤。

對於您的代碼,頭幾行根本不需要鎖,因爲它們只訪問函數參數和局部變量(規則4)。 void *data指向的數據可能需要也可能不需要鎖,具體取決於它是什麼 - 例如,如果每個線程都有自己獨立的數據(規則4),或者只有該數據被讀取(規則3),則不需要鎖定。對於LOG_INFO()函數,在您發佈的代碼中不需要額外的鎖(不存在void *data鎖),但它可能有自己的內部鎖(例如保護共享日誌)。

對於規則2的例子,如果LOCK_INFO需要一點時間你的代碼可以做這樣的事情在第一鎖較早釋放:

temp_ID = channel->id; 
temp_name = strdup(channel->name); // Should check for NULL! 
temp_delay = channel->delay_time; 

/* 
    UNLOCK HERE 
*/ 

LOG_INFO("Channel id [ %d ] Channel name [ %s ] Delay time [ %d ]", 
     temp_ID, 
     temp_name, 
     temp_delay); 
free(temp_name); 

還要注意的是,如果LOCK_INFO()使用鎖,釋放第一次鎖定也有助於規則6.

+0

Re:3,如果其他線程可能寫入,則即使讀取也需要鎖定。在這種情況下,rwlocks很有用。 –

+0

@R ..是的,但是規則1應該覆蓋該規則(例如,如果數據被寫入,則數據需要鎖;並且使用具有鎖的數據的函數必須獲取數據的鎖,即使該函數只讀取數據)。我可能可以做得更清楚。 – Brendan

1

不,它不是一個副本,該data實際上只是一個指針數據,因此,你的線程和調用者的上下文都可以訪問此相同數據。現在,如果你可以保證(線程和調用者上下文)不會同時觸及數據,那麼在線程函數中就不需要鎖定了。

1

您絕對需要擔心,因爲data是指向您的實際channel_t數據的指針。

但是,如果您想使用線程並行工作,那麼在鎖定時間長的情況下工作時間很長。更好的粒子鎖定會更好 - 但是這當然假定所做的整體操作可以分成幾部分,使數據保持一致的狀態。

2

如果您想在解鎖互斥體時讀取此通道,請使用pthread_mutex_trylock()而不是pthread_mutex_lock()。它確實相同,但pthread_mutex_trylock()不blocant,基於它的返回值 你可以這樣做:

if (pthread_mutex_trylock(your_mutex)) 
{ 
    //Read the data. 
}