2013-04-05 52 views
0

這是一個跟進this的問題。`pthread_mutex_trylock`和`pthread_mutex_lock`行爲

在該代碼中,當我沒有使用fflush(stdout)時,輸出沒有被刷新到屏幕上時,我保留了sleep(1)

#define S sleep(0) 

void* xThread_fn(void* arg) 
{ 
while(1) 
    { 
    S; 
    pthread_mutex_lock(&read_c_mutex); 
     if(!read_c) 
     { 
      pthread_mutex_unlock(&read_c_mutex); 
      printf(" X"); 
     } 
     else 
     { 
      pthread_mutex_unlock(&read_c_mutex); 
      pthread_exit(NULL); 
     } 
    fflush(stdout); <---THIS ONE HERE 
    } 

} 

但是,當我把sleep(0)沒有必要爲fflush(stdout),輸出正常更新stdout。這是爲什麼?

Q1。爲什麼sleep(0)的存在會導致輸出刷新的方式發生變化?

如果我修改代碼如下(以跟蹤執行),

#define S sleep(1) 

int read_c = 0; 
pthread_mutex_t read_c_mutex = PTHREAD_MUTEX_INITIALIZER; 

void* inputThread_fn(void* arg) 
{ 
printf("%p is Input\n",pthread_self()); 
char inputChar; 
int i = 0; 
while(1) 
{ 
    S; 
    printf("\nChecking input"); 
    scanf("%c",&inputChar); 
    if(inputChar=='C' || inputChar == 'c') 
    { 
    pthread_mutex_trylock(&read_c_mutex); 
    printf("%p has lock %d\n",pthread_self(),i); 
    read_c = 1; 
    pthread_mutex_unlock(&read_c_mutex);  
    printf("%p has UNlockED %d\n",pthread_self(),i++); 
    printf("%p is Gone!\n",pthread_self()); 
    fflush(stdout); 
    pthread_exit(NULL); 
    } 
} 
} 

void* xThread_fn(void* arg) 
{ 
    int i = 0; 
    printf("%p is X\n",pthread_self()); 
    while(1) 
    { 
    S; 
    printf("X trying for a lock\n"); 
    pthread_mutex_trylock(&read_c_mutex); 
    printf("%p has lock %d\n",pthread_self(),i); 
    if(!read_c) 
    { 
     pthread_mutex_unlock(&read_c_mutex); 
     printf("%p has UNlockED %d\n",pthread_self(),i++); 
     printf("X\n"); 
     fflush(stdout); 
    } 
    else 
    { 
     printf("%p is Gone!\n",pthread_self()); 
     pthread_mutex_unlock(&read_c_mutex); 
     fflush(stdout); 
     pthread_exit(NULL); 
    } 
    } 
} 

void* yThread_fn(void* arg) 
{ 
printf("%p is Y\n",pthread_self()); 
int i = 0; 
while(1) 
{ 
    S; 
    printf("Y trying for a lock\n"); 
    pthread_mutex_trylock(&read_c_mutex); 
    printf("%p has lock %d\n",pthread_self(),i); 
    if(!read_c) 
    { 
    pthread_mutex_unlock(&read_c_mutex); 
    printf("%p has UNlockED %d\n",pthread_self(),i++); 
    printf("Z\n"); 
    fflush(stdout); 
    } 
    else 
    { 
    printf("%p is Gone!\n",pthread_self()); 
    pthread_mutex_unlock(&read_c_mutex); 
    fflush(stdout); 
    pthread_exit(NULL); 
    } 
    } 
} 

一個樣本輸出端是

0xb6700b70 is Input 
0xb6f01b70 is Y 
0xb7702b70 is X 

Checking inputY trying for a lock 
0xb6f01b70 has lock 0 
0xb6f01b70 has UNlockED 0 
Z 
X trying for a lock 
0xb7702b70 has lock 0 
0xb7702b70 has UNlockED 0 
X 
Y trying for a lock 
0xb6f01b70 has lock 1 
0xb6f01b70 has UNlockED 1 
Z 
X trying for a lock 
0xb7702b70 has lock 1 
0xb7702b70 has UNlockED 1 
X 
Y trying for a lock 
0xb6f01b70 has lock 2 
0xb6f01b70 has UNlockED 2 
Z 
X trying for a lock 
0xb7702b70 has lock 2 
0xb7702b70 has UNlockED 2 
X 
Y trying for a lock 
0xb6f01b70 has lock 3 
0xb6f01b70 has UNlockED 3 
Z 
X trying for a lock 
0xb7702b70 has lock 3 
0xb7702b70 has UNlockED 3 
X 
Y trying for a lock 
0xb6f01b70 has lock 4 
0xb6f01b70 has UNlockED 4 
Z 
X trying for a lock 
0xb7702b70 has lock 4 
0xb7702b70 has UNlockED 4 
X 
c 
Y trying for a lock 
0xb6f01b70 has lock 5 
0xb6f01b70 has UNlockED 5 
Z 
X trying for a lock 
0xb7702b70 has lock 5 
0xb7702b70 has UNlockED 5 
X 
0xb6700b70 has lock 0 
0xb6700b70 has UNlockED 0 
0xb6700b70 is Gone! 
Y trying for a lock 
0xb6f01b70 has lock 6 
0xb6f01b70 is Gone! 
X trying for a lock 
0xb7702b70 has lock 6 
0xb7702b70 is Gone! 

Q2。我已經使用了pthread_mutex_trylock(),因爲我希望代碼在while循環中繼續,直到它獲取一個鎖來檢查read_c的值。 pthread_mutex_lock();似乎也可以實現。這使我更加困惑。 pthread_mutex_trylock();,輸出總是這樣嗎?一個X後面跟着一個Z。不會有這樣的情況,它可能會像XXZX(假設線程由操作系統切換,ythread嘗試鎖定失敗)?

回答

4

回答「trylock」問題。

pthread_mutex_trylock只會嘗試鎖定互斥鎖。如果其他人鎖定了互斥鎖,它將只返回一個錯誤並繼續運行。由於您沒有檢查返回值,因此您可能會觸摸受互斥鎖保護的數據而無需保留互斥鎖。

你的代碼相當於根本沒有任何互斥體。

pthread_mutex_trylock只能在您出於某種非常特殊的原因無法等待鎖定並且在獲取互斥失敗時回退到不同行爲的情況下使用。調用它而不檢查返回值總是一個錯誤。

爲了完全正確,您還應該檢查pthread_mutex_lock的返回值。但是你可以經常逃避不這樣做。你不能逃避不檢查trylock的返回值。

+0

好的。所以這裏錯了(在'inputThread_fn')? 'pthread_mutex_trylock(&read_c_mutex);' '的printf( 「%p具有鎖定%d \ n」 個,pthread_self()中,i);' 'read_c = 1;' '調用pthread_mutex_unlock(&read_c_mutex);'在這裏,我嘗試鎖如果我沒有得到它,我仍然可以修改數據。所以我需要一個'_lock'而不是'_trylock'。但是,如果我只是讀取數據(如'xthread_fn'和'yThread_fn'),那麼'trylock'就足夠了嗎? – 2013-04-05 12:01:23

+0

簡單的迴應是:除非你真的真的明白它解決了什麼問題,否則不要使用trylock。在大多數情況下,它不是你正在尋找的機器人。實際上,在你的特定情況下,我敢肯定你在一個緩存一致的體系結構中,根本就沒有任何互斥體,任何函數調用都會使編譯器不緩存全局變量的值,因爲讀取並寫入它是原子的(無論如何它只是一個布爾值)。這將打破所有的標準,但可能會奏效。 – Art 2013-04-05 12:06:29

+0

藝術,這是你給同時訪問一個沒有鎖定的全球性壞建議!因此,讓我在最後一句話後面添加「有時」一詞...... – alk 2013-04-05 12:11:52

1

當睡眠被稱爲進程是上下文切換出(調度出)。睡眠(0)意味着你並不是真的在睡覺。所以過程繼續執行。 Printf使用緩衝的stdout。因此,無論您打印到輸出緩衝區中,然後刷新到終端(屏幕)上。 當進程休眠緩衝區沒有被刷新,所以你不會得到輸出,除非你做顯式刷新。如果你沒有進入睡眠狀態,程序會得到一個沖洗緩衝區的機會,並立即得到輸出。 無論何時在程序中使用任何阻塞調用或休眠行爲,都會發現printf的這種行爲。如果你使用fprintf(stderr,「你的字符串」),那麼它總是會打印,而不管你是否睡覺。

相關問題