2012-01-23 75 views
3

我試圖創建4個線程同時在我的4個CPU內核運行一個函數。我調用的函數將根據val變量值更改一些循環偏移量。CreateThread參數值意外改變

我想這一點,但它不恰當地增加val櫃檯,一些線程的報告相同的價值觀,似乎隨意改變:

int val = 1; 
threads[0] = CreateThread(0, 0, my_thread_1, &val, 0, 0); 
val++; 
threads[1] = CreateThread(0, 0, my_thread_1, &val, 0, 0); 
val++; 
threads[2] = CreateThread(0, 0, my_thread_1, &val, 0, 0); 
val++; 
threads[3] = CreateThread(0, 0, my_thread_1, &val, 0, 0); 

但這似乎只是很好地工作:

int val1 = 1; 
int val2 = 2; 
int val3 = 3; 
int val4 = 4; 
threads[0] = CreateThread(0, 0, my_thread_1, &val1, 0, 0); 
threads[1] = CreateThread(0, 0, my_thread_1, &val2, 0, 0); 
threads[2] = CreateThread(0, 0, my_thread_1, &val3, 0, 0); 
threads[3] = CreateThread(0, 0, my_thread_1, &val4, 0, 0); 

這可能是什麼原因,以及它如何正確完成給線程一些參數?

這是我的函數:

DWORD WINAPI my_thread_1(void *params){ 
    int val = *(int *)params; 
... 
} 

回答

4

這只是因爲在第一個例子中,你將所有4個線程的指針傳遞給相同的內存位置。在通過指針之前遞增的事實是不重要的,因爲存儲器位置保持不變。

在你的第二個例子中,你改爲將4,互斥指針傳遞給4個線程。因此,線程都讀取獨立的值。

你可以調整你的代碼稍微幫助可維護性和靈活性:

int threadData[NTHREADS]; /* in the future this could be an array of structs */ 
HANDLE threads[NTHREADS]; 
int tt; 

for (tt = 0; tt < NTHREADS; ++tt) 
{ 
    threadData[tt] = tt + 1; /* placeholder for actual logic */ 
    threads[tt] = CreateThread(
     NULL,   /* lpThreadAttributes */ 
     0,    /* dwStackSize */ 
     my_thread_1,  /* lpStartAddress */ 
     &threadData[tt], /* lpParameter: each thread will receive its own data */ 
     0,    /* dwCreationFlags */ 
     NULL    /* lpThreadId */); 
} 

/* Since threadData and threads are local to the enclosing scope, 
* we must wait for them to finish here to ensure we don't read 
* data we no longer own 
*/ 
WaitForMultipleObjects(NTHREADS, threads, TRUE, INFINITE); 
0

多個線程同時訪問相同的內存。您應該使用互斥鎖或信號量來獨佔訪問臨界區域中的變量。

+0

不過,是保證第二個例子好好工作? – Rookie

+1

@Rookie現在是代碼,是的。 –

+2

鎖在這裏絕對不是答案。答案是不共享數據。這總是比鎖好,它在語義上也是正確的。 –

1

在第一種情況下,你傳遞同一個對象的所有線程。在第二種情況下,你傳遞了不同的對象。

在這兩種情況下,有一個潛在的問題是,如果它創建線程的函數返回,那麼所有創建的線程將指針int不存在了,因爲所有的int對象都是本地對象的功能,創建線程。這會調用未定義的行爲。

因此,如果函數不等待回報,那麼在這種情況下,你不應該傳遞指向本地對象,而是通過動態分配的對象:

int *v1 = new int; 
threads[0] = CreateThread(0, 0, my_thread_1, v1 , 0, 0); 
+0

我明白了,所以,第二個例子將保證正常工作,如果我的函數創建那些線程不會死在我的線程停止之前? – Rookie

+1

@Rookie:是的。如果創建線程的函數在線程完成其作業之後才返回,那麼它是明確定義的。 – Nawaz

+3

當然,或者等到所有線程都吃掉了傳遞的值,並且不再需要它或者已經創建了本地副本。 –