#include <stdio.h>
#include <pthread.h>
typedef struct {
int threadNum;
}thread_args;
void thread_func(void*vargp){
thread_args*id=(thread_args*)vargp;
printf("%i\n",id->threadNum);
}
int main() {
for(int i=0;i<20;i++) {
pthread_t id;
thread_args args;
args.threadNum=i;
pthread_create(&id,NULL,thread_func,(void*)&args);
}
pthread_exit(NULL);
return 0;
}
改编自https://www.geeksforgeeks.org/multithreading-c-2/。
因此,这有望输出:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
但是以随机顺序随机播放以说明线程的并发性。
这里的问题是实际上会打印出以下内容:
4
9
10
5
11
12
13
8
4
4
17
6
18
7
15
19
6
14
19
16
如您所见,有重复的数字,只是简单地跳过了0-3。
我之前在其他框架中也曾做过并发,而且我也看到过类似的问题:这里发生的是i
被作为引用传递(我认为!),因此{{1 }}循环递增for
,它在所有线程参数变量中都递增。
如何避免这种情况?
注意:一切都可以100%正确地链接,我在macOS上。
PS:对不起,如果重复的话,我对此并不十分了解。
答案 0 :(得分:4)
您的for循环中有一个UB。您正在创建一个名为args
的变量,在其中分配一个值,将其作为对线程的引用传递给以后执行,并在for循环结束时销毁它。然后再做一次,可能会覆盖该区域。
为解决该问题,我建议进行以下修改:
int main() {
thread_args args[20] = {0};
pthread_t id[20] = {0};
for(int i=0;i<20;i++) {
args[i].threadNum=i;
pthread_create(&id[i],NULL,thread_func,(void*)&args[i]);
}
for(int i = 0; i < 20; i++)
pthread_join(id[i], NULL);
return 0;
}
答案 1 :(得分:1)
实际上,这是一个竞赛条件。您将void
pointer 传递给参数struct,但是(可能)为每个参数struct重用相同的内存地址。因此,以后访问它时,可能会读取修改后的内存。试试这个:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct {
int threadNum;
}thread_args;
void thread_func(void* vargp){
thread_args* id = (thread_args*)vargp;
printf("%i\n", id->threadNum);
free(vargp);
}
int main() {
for(int i=0;i<20;i++) {
pthread_t id;
thread_args* args = malloc(sizeof(thread_args));
args->threadNum = i;
pthread_create(&id, NULL, thread_func, (void*)args);
}
pthread_exit(NULL);
return 0;
}
感谢Kamil Cuk指出了另一个比赛条件。
请注意,由于代码从不加入线程,因此该代码段可能仍会泄漏,因此可能永远不会调用free()
。