我使用for循环来创建多个线程并将索引i作为参数传递,如下所示:
pthread_t p[count];
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
}
然后我尝试检索i的值:
void *somefunc (void* ptr){
int id = *(int*)ptr;
}
然而,我注意到有时候,线程中的id会有重叠的值,我怀疑是由于for循环更新的索引在线程能够检索值之前(因为我传入了指针,而不是价值本身)。有没有人有任何建议来克服这个问题,而不会减慢for循环?
由于
答案 0 :(得分:2)
这种情况正在发生,因为一旦您将指针传递给i
,您现在有多个线程使用相同的值。这导致数据竞争,因为第一个线程正在修改i
,而您的第二个线程期望它永远不会改变。您始终可以分配临时int并将其传递给线程函数。
pthread_create(&p[i], NULL, &somefunc, new int(i));
这将在动态存储(堆)中分配一个整数,并使用值i
对其进行初始化。然后,指向新分配的整数的指针将传递给线程函数。
然后在线程函数中,您可以获取已经传递的值,然后删除int对象。
void *somefunc (void* ptr){
int id = *(int*)ptr;
delete (int*)ptr;
}
[建议:Avoid C style casts.]
答案 1 :(得分:2)
你让这有点太复杂了:
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
您只想传递值,而不是指向它的指针,因此传递(void*)i
。你正在向每个线程传递一个指向i
的指针,该指针有问题:
i
可能会在线程尝试从其地址读取时留下范围 - 其他一些变量可能存在,或者内存可能与未使用的内容一起使用,其中包含了谁知道什么? / LI>
i
值所以:
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)i);
...
void *somefunc (void* id_cast_to_voidptr){
int id = (int)id_cast_to_voidptr;
}
答案 2 :(得分:2)
正如其他人所说,你正在传递一个指向另一个线程(父节点)正在修改的对象的指针,并在没有任何同步的情况下访问它。这是一个错误。
至少有3种解决方案:
为单个new
分配(通过C ++中的malloc
或C中的int
)空间,并让新线程负责释放它。这可能是最糟糕的解决方案,因为现在您有一个额外的故障情况需要处理(分配失败),因此它使代码变得复杂和混乱。
将整数转换为void *
并返回。这肯定适用于任何现实世界的POSIX系统,但它不能“保证”工作,也许更令人讨厌的是,它可能会引发警告。您可以通过uintptr_t
进行中间演员来避免警告。
不是传递索引,而是传递地址:
pthread_create(&amp; p [i],NULL,&amp; somefunc,&amp; p [i]);
然后start函数可以通过减去p
来恢复索引(如果它需要它):
int id = (pthread_t *)ptr - p;
答案 3 :(得分:0)
我认为最好的答案是在开头声明一个args数组,其大小与您打算创建的线程数相同。
这样,这些值永远不会被覆盖或处于竞争状态。
int args[count];
for (int i = 0; i < count; i++){
args[i]=i;
pthread_create(&p[i], NULL, &somefunc, (void*)args[i]);
}
答案 4 :(得分:-1)
您可以在 main 函数的开头声明一个任务 id 数组。无论何时创建线程,您都可以发送该数组的索引以防止参数被覆盖。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUM_THREADS 8
void *PrintHello(void *threadid)
{
long taskid;
sleep(1);
taskid = (long) threadid;
printf("Hello from thread %ld\n", taskid);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
long taskids[NUM_THREADS];
int rc;
for(long t=0;t<NUM_THREADS;t++) {
printf("Creating thread %ld\n", t);
taskids[t] = t;
rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}