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

时间:2013-04-19 02:17:22

标签: c multithreading pthreads

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

由于

5 个答案:

答案 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>
  • 循环中的下一次迭代将覆盖该值,这意味着所有线程在取消引用指针时可能会看到值“count”,如果它没有像上面那样被破坏,除了极少数情况在循环期间挂起启动线程的位置允许它生成的线程读取某些较早的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种解决方案:

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

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

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

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

  4. 然后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);
}