2012-01-23 40 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

当然,或者等到所有线程都吃掉了传递的值,并且不再需要它或者已经创建了本地副本。 –