2013-08-23 67 views
1

在下面的代碼中,我只是想看看我是否能夠從每個線程插入一個元素到數組中。它按預期工作。但後來我想知道,在什麼情況下,這裏可能會出現競賽狀況。我真的需要在這裏變動嗎,還是信號量?我試圖刪除信號量和易變的關鍵字,仍然有效。我想在這裏引發並看到競賽情況。在同一行上,我可以從每個線程創建一個節點,並將所有節點放入鏈接列表中?這些都是虛構的場景..!C多線程:競態條件場景

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <semaphore.h> 
#include "small_appl.h" 

void * thread_func(void * arg); 

int itr=0; 
volatile int idx=0; //array index variable 
sem_t sem1; 
int arr_th[5];  //array where each thread will insert an element 

int func_pointed(int a,int num_t) 
{ 
    pthread_t arr_thr[num_t]; 
    int iter; 
    //create threads 
    for(iter=0;iter<num_t;iter++) 
    { 
     pthread_create(&arr_thr[iter],NULL,thread_func,(void *)a); 
    } 

    for (iter=0;iter<num_t;iter++) 
    { 
     pthread_join(arr_thr[iter],NULL); 
    } 
} 

int main(void) 
{ 
    int ip1=5,ip2=10,rev; 

    rev=sem_init(&sem1,0,0); 
    s_type dev_s={ 
        .f_ptr=func_pointed, 
        .str="Diwakar", 
        .val=5 
       }; 

    //initialize semaphore to 1 
    sem_post(&sem1);  

    func_aux(ip1,dev_s); 

    for(rev=0;rev<5;rev++) 
    { 
    printf("array : %d ",arr_th[rev]); 
    } 

} 

void * thread_func(void * arg) 
{ 
    sem_wait(&sem1); 
    printf("Got sema\n"); 
    arr_th[idx]=itr; 
    idx++; itr++; 
    printf("Releasing sema\n"); 
    sem_post(&sem1); 

    sleep(5); 
} 
+4

在C中,'volatile'並不意味着你的想法。特別是,它不同於一個原子變量或任何進行內存同步的東西。 –

+0

競態條件不容易產生。C語言中的volatile只是爲了告訴編譯器不要爲這個變量優化,而不是爲了多線程目的。 – JackyZhu

+0

在此代碼中,您不需要任何位置的「volatile」*。你也不需要信號量,因爲無論如何你真正使用它是一個互斥量(如果你拋出信號量,你就需要*)*。 – WhozCraig

回答

1

要創建或模仿其中線程覆蓋另一個線程所做的工作的情況,然後取出信號和戰略上放置的睡眠,如:

void * thread_func(void * arg) 
{ 
    //sem_wait(&sem1); 
    //printf("Got sema\n"); 
    arr_th[idx]=itr; 
    // print arr_th[idx] 
    sleep(5);  <<== gives the threads more of a chance to wipe-out each other 
    // print arr_th[idx] 
    idx++; itr++; 
    //printf("Releasing sema\n"); 
    //sem_post(&sem1); 

    sleep(5); 
} 

您可以添加一些printf語句明確突出問題。

volatile告訴編譯器不要刪除未使用或至少看起來未被使用的變量。

您可以從多個線程更新鏈接列表,但必須序列化更新列表中鏈接(next和/或prev)的代碼的關鍵部分。

在Windows XP及以上版本中,CRT是線程安全的,因此每個線程都可以發出malloc(),printf之類的內容,而不必序列化這些調用的線程。

+0

你能否給我提供一些關於序列化關鍵部分意味着什麼的提示? –

+0

@DiwakarSharma,基本思想是隻允許一個線程在任何時候運行一小段指令。記住所有的線程通常運行相同的代碼,但是它的某些部分只允許一個線程執行它。搜索互斥鎖或信號量,並調用系統函數來完成此操作。但是,如果您瞭解信號量的概念,那麼您可以編寫自己的序列化代碼。要解釋更多內容需要一章,但要了解信號量的概念以及如何用C代碼實現。 – JackCColeman

1

volatile指示編譯器該變量隨時可以更改。這意味着對變量的每個引用都必須導致從內存中讀取(而不是重用寄存器中的值的副本)。

volatile int i; 
if(i==0) return 
if(i==1) ... 

如果volatile關鍵字是不存在,編譯器可能會讀取變量到寄存器一次,並檢查它的0和1

如果你的主程序您等待IDX變量是一定的價值是這樣的,你應該讓它volatile

while(idx==10); 

揮發性不會使它線程安全,這是一個不同的問題。事實上,因爲你保護了這段代碼,所以你不希望idx從一次讀取變爲下一次,所以你不需要volatile。

如果你想產生競爭條件(檢測部分代碼被拆分),我建議設置2個值,你在2個單獨的指令中增加,並在一個連續的while循環(不睡覺!減少關鍵部分分裂的可能性)。在主循環中,不斷檢查值是否相等(再次不睡覺)。如果它們不相等,則代碼的兩個部分之一被拆分。還要看看程序集以確保編譯器沒有優化某些東西。