2012-08-02 127 views
1

我有這個簡單的線程創建progrm在C++中,當全局聲明RW鎖時,progrmm按預期方式執行,但是當相同的鎖定聲明是本地(即函數內部)只有一個線程執行,另一個線程掛起。線程掛起在pthread_rwlock_t

工作:

#include <iostream> 
#include <pthread.h> 

using namespace std; 
int i = 0; 
**pthread_rwlock_t mylock;** //GLOBAL 

void* IncrementCounter(void *dummy) 
{ 
    cout << "Thread ID " << pthread_self() << endl; 
    int cnt = 1; 
    while (cnt < 50) 
    { 
     pthread_rwlock_wrlock(&mylock); 
     ++i; 
     pthread_rwlock_unlock(&mylock); 
     ++cnt; 
    cout << "Thread ID (" << pthread_self() << ") Incremented Value : " << i << endl; 
    } 

} 
int main() 
{ 
     pthread_t thread1,thread2; 
     int ret, ret1; 
     ret = pthread_create(&thread1,NULL,IncrementCounter,NULL); 
     ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL); 
     pthread_join(thread1,NULL); 
     pthread_join(thread2,NULL); 

} 

* 非工作: *

#include <iostream> 
#include <pthread.h> 

using namespace std; 
int i = 0; 

void* IncrementCounter(void *dummy) 
{ 
    cout << "Thread ID " << pthread_self() << endl; 
    int cnt = 1; 
    **pthread_rwlock_t mylock;** //LOCAL 
    while (cnt < 50) 
    { 
     pthread_rwlock_wrlock(&mylock); 
     ++i; 
     pthread_rwlock_unlock(&mylock); 
     ++cnt; 
    cout << "Thread ID (" << pthread_self() << ") Incremented Value : " << i << endl; 
    } 

} 
int main() 
{ 
     pthread_t thread1,thread2; 
     int ret, ret1; 
     ret = pthread_create(&thread1,NULL,IncrementCounter,NULL); 
     ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL); 
     pthread_join(thread1,NULL); 
     pthread_join(thread2,NULL); 

} 

可能是什麼可能的原因?

回答

4

在任何情況下,您都無法正確初始化mylock變量 - 在第一種情況下,您剛剛獲得「幸運」。在全球情況下正確的初始化是:

pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER; 

在當地的情況下,如果你希望你的線程能夠訪問相同鎖,那麼它已經被宣佈static

static pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER; 

這就是你想要的,因爲你正在保護對全球i的訪問。鎖應該與數據相關聯,所以如果i是全球性的,那麼確實mylock也是全球性的。


如果你真的非靜態鎖(在這種情況下,你不這樣做),你可以使用:

pthread_rwlock_t mylock; 

pthread_rwlock_init(&mylock, NULL); 

依次爲:

pthread_rwlock_destroy(&mylock); 

在函數結束時。

+0

謝謝大家澄清。我知道爲全局變量設置兩個鎖沒有意義。但是如果有兩個鎖,那麼它們將會是不同的鎖,所以如果一個鎖解鎖,另一個將鎖定,爲什麼它會死鎖? 不應該用2個不同的鎖來鎖定一個全局變量嗎?你能否詳細說明一下? – user1570478 2012-08-02 08:11:05

+0

@ user1570478:這是死鎖,因爲您沒有正確初始化鎖,不是因爲有兩個鎖。當你使用未初始化的鎖時,任何事情都可能發生。 – caf 2012-08-02 08:27:11

0

原因很清楚,你甚至可以自己這麼說......在工作版本中,變量是全局變量,而在非工作變量中,變量是局部變量。

在調用期間,局部變量只在函數內部是已知的。所以如果一個函數被調用兩次,那麼這兩個調用的變量都是唯一的。

如果你想使用一個局部變量,你可以將它標記爲static,因爲它使得它在函數的所有調用之間都是「靜態的」。

我建議你閱讀更多關於變量範圍和生命週期。

+0

謝謝你們的澄清。我知道爲全局變量設置兩個鎖沒有意義。但是如果有兩個鎖,那麼它們將會是不同的鎖,所以如果一個鎖解鎖,另一個將鎖定,爲什麼它會死鎖?不應該用2個不同的鎖來鎖定一個全局變量嗎?你能否詳細說明一下? – user1570478 2012-08-02 08:11:34

+0

@ user1570478由於鎖未正確初始化,它可能會死鎖?查看來自caf的回答。 – 2012-08-02 08:24:47

1

除了其他答案的內容之外,還應該考慮在C和C++中,所有帶有靜態存儲的變量(例如第一個示例中的mylock)都被初始化爲零。 簡化,pthread_rwlock_tstruct

在第一個示例中,mylock具有靜態存儲持續時間,因此其所有內部成員都初始化爲零。偶然地,這相當於pthread_rwlock_t的「解鎖」狀態,因爲在另一個答案中提到的宏PTHREAD_RWLOCK_INITIALIZER正好將所有東西初始化爲零;在nptl/sysdeps/pthread/pthread.h你可以找到:

#define PTHREAD_RWLOCK_INITIALIZER \ 
{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } 

因此,所有你的第一個例子的運行總是會出現相同的行爲(即鎖將開始解鎖)。

在第二個示例中,mylock未初始化,因爲它具有自動存儲持續時間。這種行爲將取決於其他值發生在未初始化的內存區域上。大多數情況下,開始處於「鎖定」狀態的鎖定,但如果運氣夠好(不幸),就會開始解鎖。

+0

請注意,這僅適用於pthread的一個特定實現 - 在其他實現中,「PTHREAD_RWLOCK_INITIALIZER」可能非零(否則根本不需要存在!)。 – caf 2012-08-02 08:33:23

+0

正確;我想'PTHREAD_RWLOCK_INITIALIZER'是爲了交叉實現和/或跨版本的兼容性,而不是良好的編碼實踐。 – 2012-08-02 17:44:56

+0

是的,例如pthreads-w32使用'((pthread_rwlock_t)-1)'。 – caf 2012-08-03 05:34:08