背景题目
有一个线程函数thread_func,它的入参是一个整数,它的功能是打印出这个整数。要求循环启动10个线程,打印出1~10
错误写法
#include <pthread.h>
#define MAXN 10
void* thread_func(void* arg)
{
printf("arg = %d\n", *(int*)arg);
}
int main()
{
pthread_t tid[MAXN];
for (int i = 0; i < MAXN; i++) {
pthread_create(&tid[i], NULL, thread_func, &i);
}
for (int i = 0; i < MAXN; i++) {
pthread_join(tid[i], NULL);
}
return 0;
}
执行结果

可以看到,打印出来的全都是10,而不是每轮循环传入的i
原因分析:我们传入的,不是变量i的值,而是i的地址,相当于一个指向i的指针。
因此在打印出该地址的i的值时,i的值已经被循环所改变了。
那么该怎么写呢?
解决方法1-数组
通过数组存储传入的变量值,可以保证参数不发生变化
#include <pthread.h>
#define MAXN 10
void* thread_func(void* arg)
{
printf("arg = %d\n", *(int*)arg);
}
int main()
{
int a[MAXN]; // 解决方法增加的数组
pthread_t tid[MAXN];
for (int i = 0; i < MAXN; i++) {
a[i] = i;
pthread_create(&tid[i], NULL, thread_func, &a[i]);
}
for (int i = 0; i < MAXN; i++) {
pthread_join(tid[i], NULL);
}
return 0;
}
执行结果

但该方法的缺点是显而易见的:数组a占用了额外的空间。
方法2-malloc
将每次要传入的参数,通过malloc分配出一块专门的内存存放,用完释放。
#include <pthread.h>
#define MAXN 10
void* thread_func(void* arg)
{
printf("arg = %d\n", *(int*)arg);
free(arg); // 用完释放
}
int main()
{
pthread_t tid[MAXN];
for (int i = 0; i < MAXN; i++) {
int *cnt = malloc(sizeof(int)); // 分配内存
*cnt = i; // 赋值
pthread_create(&tid[i], NULL, thread_func, cnt);
}
for (int i = 0; i < MAXN; i++) {
pthread_join(tid[i], NULL);
}
return 0;
}
这样,每次传入的都是一个全新的地址来存储i的值。该方法需要注意的是要及时释放arg指向的内存,避免内存泄漏。
方法3-xjb转换指针
#include <pthread.h>
#define MAXN 10
void* thread_func(void* arg)
{
printf("arg = %d\n", arg); // 注意这里不一样了
}
int main()
{
pthread_t tid[MAXN];
for (int i = 0; i < MAXN; i++) {
pthread_create(&tid[i], NULL, thread_func, (void*)i); // 把i解释为(void*)
}
for (int i = 0; i < MAXN; i++) {
pthread_join(tid[i], NULL);
}
return 0;
}
这里把i强制当作一个void*类型指针指向的地址传入,这样拿到的是一份拷贝,当然,输出时,不需要解引用。
这方法真的是emmm…
本文探讨了在使用多线程时遇到的一个常见问题:如何正确地将参数传递给线程函数。通过三个不同的解决方案,包括使用数组、动态内存分配以及类型转换,展示了如何避免因共享变量导致的打印错误。每个方法都有其优缺点,例如数组占用额外空间,动态内存需要手动管理,而类型转换则可能存在潜在风险。
635






