2013-12-16 149 views
4

我要創建兩個線程,這都應該是這樣的:關於並行POSIX線程

P1:

while(1) { 
    printf("1"); 
    printf("2"); 
    printf("3"); 
    printf("4"); 
} 
return NULL; 

P2:

while(1) { 
    printf("5"); 
    printf("6"); 
    printf("7"); 
    printf("8"); 
} 
return NULL; 

據我平行的知識它將不會打印12345678,而是由於缺乏同步而導致數字完全隨機變化。

然而,當我試圖複製它在真正的代碼它使印刷1234了幾下,然後切換到5678,打印了幾次,並回到1234

是我線程的理解錯誤,或我的代碼不等於問題?

void *print1(void *arg) { 
    while(1) { 
     printf("1"); 
     printf("2"); 
     printf("3"); 
     printf("4\n"); 
    } 
    return NULL; 
} 

void *print2(void *arg) { 
    while(1){ 
     printf("5"); 
     printf("6"); 
     printf("7"); 
     printf("8\n"); 
    } 
    return NULL; 
} 


int main() { 
    pthread_t tid1, tid2; 
    pthread_create(&tid1, NULL, print1, NULL); 
    pthread_create(&tid2, NULL, print2, NULL); 
    pthread_join(tid1, NULL); 
    pthread_join(tid2, NULL); 
    return 0; 

} 
+1

一個詞:buffering。輸出流不會隱式刷新,直到遇到新行。 – Kninnug

+0

我該怎麼做? fflush(標準輸出)?我相當新的 – Pulz

+0

你絕對可以嘗試。雖然它可能仍然會產生相同的輸出。請參閱答案以獲得更多解釋。 – Kninnug

回答

1

在多線程應用程序內部訪問共享數據時,保護共享數據總是非常重要。在你的情況下,你有兩個線程同時訪問標準輸出,因此你有一個競爭條件,其中兩個線程競相獲取stdout。因此,我冒昧地讓您的程序適應標準輸出受互斥鎖保護的情況。在使用stdout之前,我們鎖定一個互斥鎖,另一個線程也會嘗試鎖定互斥鎖,但兩者不能同時在同一時間完成。因此試圖鎖定的第二個線程進入睡眠狀態。

正如其他人告訴你的,看起來你最初編寫的程序做出了不錯的輸出,或多或少都是巧合,在其他系統上,你無法保證這一點,並且兩個線程的輸出可能混淆起來。在輸出像

1256734 
8 
5671234 
8 

結束等

現在,你可能會認爲,一旦互斥量被釋放其他將自動接管,但最多也就是調度。因此在下面的例子中,程序在輸出5678之前可能會執行幾個1234。但它將始終是1234或5678,而這些輸出不會混合。如果你真的想要交替兩個線程,你必須有更復雜的輸出和查找條件變量,例如,pthread API也支持這些。

#include<pthread.h> 
#include<stdio.h> 

void *print1(void *arg) { 
    pthread_mutex_t* lock = arg; 
    while(1) { 
     /*now we do output from one thread while we lock the 
     *mutex from the main function.*/ 
     pthread_mutex_lock(lock); 
     printf("1"); 
     printf("2"); 
     printf("3"); 
     printf("4\n"); 
     fflush(stdout); 
     /*now we must lock the lock, because otherwise 
     *the other thread can't lock the mutex and if 
     *we would try to lock the mutex again we would 
     *create a deadlock, hower recursive locking is 
     *possible, but beyond the scope of my anwer.*/ 
     pthread_mutex_unlock(lock); 
    } 
    return NULL; 
} 

void *print2(void *arg) { 
    /*see the note in the frist thread*/ 
    pthread_mutex_t* lock = arg; 
    while(1){ 
     pthread_mutex_lock(lock); 
     printf("5"); 
     printf("6"); 
     printf("7"); 
     printf("8\n"); 
     fflush(stdout); 
     pthread_mutex_unlock(lock); 
    } 
    return NULL; 
} 


int main() { 
    pthread_t tid1, tid2; 
    /*lets create a lock to protect our shared resources 
    *in this case the standard output. 
    */ 
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 
    /*make sure that the mutex is available inside the thread 
    *by sending a pointer to the mutex as fourth argument to 
    *phtread_create.*/ 
    pthread_create(&tid1, NULL, print1, &lock); 
    pthread_create(&tid2, NULL, print2, &lock); 
    pthread_join(tid1, NULL); 
    pthread_join(tid2, NULL); 
    return 0; 
} 
5

多線程時,您不能依賴時序假設。

對此問題的解釋是,循環內的printf s的執行時間很短,可以在給定的時間量內執行。

3

我對線程的理解是錯誤的還是我的代碼不等於問題?

都沒有。您的兩個線程恰好按您預期的方式安排在您的系統上。有明顯的同步有很多原因,但它是相當不可預測的,因爲OS調度程序會在系統忙碌時暫停一個或多個線程。在運行示例程序的同時,您可能會嘗試在多個線程中運行繁重的工作負載,並查看是否有些事情會感到困惑。

這是造成數千個多線程程序中意外錯誤的原因,也是我們需要互斥鎖,信號量,原子寫入和複雜線程調試工具(如helgrind或其等價物)的原因。在處理線程共享數據時,證明沒有死鎖或其他同步問題是非常困難的事情。

+0

「我們需要的原因」和helgrind☺ –

+0

@JonasWielicki好點;將添加。 – ldrumm