如何将for循环的索引作为pthread_create的参数传递

我正在使用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循环?

谢谢

发生这种情况是因为一旦你将指针传递给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; } 

[建议: 避免C风格的演员阵容。 ]

你让这有点太复杂了:

 for (int i = 0; i < count; i++){ pthread_create(&p[i], NULL, &somefunc, (void*)&i); 

你只想传递值,而不是指向它的指针,所以传递(void*)i 。 你正在向每个线程传递一个指向i的指针,它有问题:

  • i可能会在线程尝试从其地址读取时留下范围 - 其他一些变量可能会在那里或者内存可能会闲置在未使用的内容中谁知道什么东西留在其中
  • 循环中的下一次迭代将覆盖该值,这意味着所有线程在取消引用指针时可能会看到值“count”,如果它没有像上面那样被破坏,除了极少数情况下发起循环期间线程被挂起,允许它生成的线程读取一些早期的值

所以:

 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; } 

正如其他人所说,你正在传递一个指针,该指针被另一个线程(父节点)修改并在没有任何同步的情况下访问它。 这是一个错误。

至少有3种解决方案:

  1. 为单个int分配(通过C中的C ++或malloc中的new )空间,并让新线程负责释放它。 这可能是最糟糕的解决方案,因为现在您有一个额外的故障情况需要处理(分配失败),因此它使您的代码变得复杂和混乱。

  2. 将整数转换为void *并返回。 这肯定适用于任何真实的POSIX系统,但它不能“保证”工作,也许更令人讨厌的是,它可能会引发警告。 您可以通过uintptr_t通过中间演员来避免警告。

  3. 传递地址而不是传递索引:

    pthread_create(&p [i],NULL,&somefunc,&p [i]);

然后start函数可以通过减去p来恢复索引(如果它需要任何东西):

 int id = (pthread_t *)ptr - p; 

我认为最好的答案是在开头声明一个args数组,其大小与您打算创建的线程数相同。

这样,这些值永远不会被覆盖或处于竞争状态。

 int args[count]; for (int i = 0; i < count; i++){ args[i]=i; pthread_create(&p[i], NULL, &somefunc, (void*)args[i]); }