[英]How can I pass the index of a for loop as the argument for pthread_create
I am using a for loop to create a number of threads and passing the index i as an argument as follows:我正在使用 for 循环来创建多个线程并将索引 i 作为参数传递,如下所示:
pthread_t p[count];
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
}
Then I attempt to retrieve the value of i:然后我尝试检索 i 的值:
void *somefunc (void* ptr){
int id = *(int*)ptr;
}
However, I noticed that sometimes, id in the threads will have overlapping values which I suspect is due to the index of the for loop updating before the thread is able to retrieve the value (since I passed in the pointer, as opposed to the value itself).但是,我注意到有时,线程中的 id 会有重叠的值,我怀疑这是由于在线程能够检索值之前更新了 for 循环的索引(因为我传入了指针,而不是值本身)。 Does anyone have any suggestions to overcome this issue without slowing down the for loop?
有没有人有任何建议可以在不减慢 for 循环的情况下克服这个问题?
Thanks谢谢
This is happening because once you pass a pointer to i
you now have multiple threads using the same value.发生这种情况是因为一旦您将指针传递给
i
您现在就有多个线程使用相同的值。 This causes a data race because the first thread is modifying i
and your second thread is expecting it to never change.这会导致数据竞争,因为第一个线程正在修改
i
而您的第二个线程期望它永远不会改变。 You can always allocate a temporary int and pass it to the thread function.您始终可以分配一个临时 int 并将其传递给线程函数。
pthread_create(&p[i], NULL, &somefunc, new int(i));
This will allocate an integer in dynamic storage (heap) and initialize it with the value of i
.这将在动态存储(堆)中分配一个整数,并使用
i
的值对其进行初始化。 A pointer to the newly allocated integer will then be passed to the thread function.然后将指向新分配的整数的指针传递给线程函数。
Then in the thread function you can take the value passed as you already do and then delete the int object.然后在线程函数中,您可以像已经做的那样获取传递的值,然后删除 int 对象。
void *somefunc (void* ptr){
int id = *(int*)ptr;
delete (int*)ptr;
}
[Suggestion: Avoid C style casts. [建议: 避免 C 风格的强制转换。 ]
]
As others have said, you're passing a pointer to an object that's being modified by another thread (the parent) and accessing it without any synchronization.正如其他人所说,您正在传递一个指向正在被另一个线程(父线程)修改的对象的指针,并在没有任何同步的情况下访问它。 This is an error.
这是一个错误。
There are at least 3 solutions:至少有3种解决方案:
Allocate (via new
in C++ or malloc
in C) space for a single int
, and have the new thread be responsible for freeing it.为单个
int
分配(通过 C++ 中的new
或 C 中的malloc
)空间,并让新线程负责释放它。 This is probably the worst solution because now you have an extra failure case to handle (failure to allocate) and thus it complicates and clutters your code.这可能是最糟糕的解决方案,因为现在您有一个额外的失败案例要处理(分配失败),因此它使您的代码复杂化和混乱。
Cast the integer to void *
and back.将整数转换为
void *
并返回。 This will surely work on any real-world POSIX system, but it's not "guaranteed" to work, and perhaps more annoyingly, it may incur warnings.这肯定会在任何现实世界的 POSIX 系统上工作,但它不能“保证”工作,也许更烦人的是,它可能会引起警告。 You can avoid the warnings with an intermediate cast through
uintptr_t
.您可以通过
uintptr_t
使用中间uintptr_t
来避免警告。
Instead of passing an index, pass an address:不传递索引,而是传递地址:
pthread_create(&p[i], NULL, &somefunc, &p[i]); pthread_create(&p[i], NULL, &somefunc, &p[i]);
Then the start function can recover the index (if it needs it for anything) by subtracting p
:然后 start 函数可以通过减去
p
来恢复索引(如果它需要它):
int id = (pthread_t *)ptr - p;
You've made this a little too complicated:你让这有点太复杂了:
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
You just want to pass the value, not a pointer to it, so pass (void*)i
.您只想传递值,而不是指向它的指针,因此传递
(void*)i
。 As is, you're passing each thread a pointer to i
which has problems:照原样,您正在向每个线程传递一个指向
i
的指针,该指针存在问题:
i
will likely have left scope by the time the thread tries to read from its address - some other variable might be there instead or the memory might be sitting around unused with who-knows-what left in iti
可能已经离开了范围 - 可能存在其他一些变量,或者内存可能处于未使用状态,不知道还剩下什么i
valuei
值So:所以:
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;
}
I think the best answer is to declare an array of args at the beginning, with the same size as the amount of threads you intend to create.我认为最好的答案是在开始时声明一个 args 数组,其大小与您打算创建的线程数量相同。
That way those values are never overwritten or in a race condition.这样,这些值永远不会被覆盖或处于竞争状态。
int args[count];
for (int i = 0; i < count; i++){
args[i]=i;
pthread_create(&p[i], NULL, &somefunc, (void*)args[i]);
}
You can declare an array of tasks id at the beginning of the main function.您可以在 main 函数的开头声明一个任务 id 数组。 Whenever you create the thread you can send the index of that array to prevent the overtwriting of the parameter.
无论何时创建线程,您都可以发送该数组的索引以防止覆盖参数。
#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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.