我正在使用malloc为数组分配内存。我意识到,如果我在线程内使用malloc且该线程停止执行,则无法访问上述数组。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREADS 2
#define N 4
void *threadWithoutMalloc(int *vector)
{
int i;
for (i = 0; i < N; i++)
{
vector[i] = i + 1;
}
return NULL;
}
void *threadWithMalloc(int *vector)
{
vector = malloc(sizeof(int) * N);
int i;
for (i = 0; i < N; i++)
{
vector[i] = i + 1;
}
return NULL;
}
int main()
{
//Generic stuff
pthread_t *threads;
threads = malloc(NUM_THREADS * sizeof(pthread_t));
int rc;
long t;
int **pointer_vector = malloc(N * sizeof(int *));
//Allocating the vector before entering the thread
pointer_vector[0] = malloc(sizeof(int)*N);
rc = pthread_create(&threads[0], NULL, (void *)threadWithoutMalloc, pointer_vector[0]);
if (rc)
{
printf("Error! Code %d\n", rc);
}
//Allocating the vector inside the thread
rc = pthread_create(&threads[1], NULL, (void *)threadWithMalloc, pointer_vector[1]);
if (rc)
{
printf("Error! Code %d\n", rc);
}
//Waiting for the threads to finish executing
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
//This works
printf("%d\n", pointer_vector[0][0]);
//This results in a segmentation fault
printf("%d\n", pointer_vector[1][0]);
return 0;
}
为什么会这样?我目前的假设是,线程运行过程后,其内存将被释放。但是,我正在使用动态分配,并将结果存储在main()
上声明的变量中。我只想了解发生了什么事。
答案 0 :(得分:4)
threadWithMalloc
永远不会将分配的存储的地址发送回其调用方或主线程。它使用参数vector
声明,然后为vector
分配一个值:
vector = malloc(sizeof(int) * N);
所有这些操作就是更改参数的值,该值实际上是该函数的局部值。更改函数中的参数不会更改在主例程中传递的参数。因此,在主例程中pointer_vector[1]
不变。
要解决此问题,让我们首先修复例程声明。 pthread_create
采用类型为void *(*)(void *)
的参数,该参数是指向一个例程的指针,该例程采用void *
参数并返回void *
结果。因此,线程例程应该声明为带有void *
参数并返回void *
结果的例程,例如:
void *threadWithoutMalloc(void *parameter)
现在,在例程中,threadWithoutMalloc
想要一个int *
,而不是void *
。我们可以通过赋值来满足这一要求:
int *vector = parameter;
然后,当我们为threadWithoutMalloc
创建线程时,无需铸造指针就可以做到:
rc = pthread_create(&threads[0], NULL, threadWithoutMalloc, pointer_vector[0]);
您的编译器应该向您发出有关pthread_create
代码的警告-将例程投射到void *
是一个不好的信号(并且其行为未由C标准定义),并且结果void *
还必须由编译器转换为参数类型void *(*)(void *)
,该参数类型也具有C标准未定义的行为,并且违反了约束。如果您的编译器没有为此提供警告,则应在编译器中启用更多警告。
对于threadWithoutMalloc
,上面的代码将其传递给int *
,这对于只接收int *
的东西是很好的。对于threadWithMalloc
,我们希望它为我们提供int *
。一种实现方法是向其传递一个指向int *
的指针,该指针为其赋予了我们希望其存储int *
的空间地址。为此,我们可以向其传递pointer_vector[1]
的地址:
rc = pthread_create(&threads[1], NULL, threadWithMalloc, &pointer_vector[1]);
然后,threadWithMalloc
我们再次要修改其声明:
void *threadWithMalloc(void *parameter)
并将参数分配给所需类型的对象:
int **vector = parameter;
然后,由于vector
是int *
本身的指针,而不是int *
本身,因此我们将vector
更改为*vector
以下代码:
(*vector) = malloc(sizeof(int) * N);
int i;
for (i = 0; i < N; i++)
{
(*vector)[i] = i + 1;
}
向主线程提供int *
的另一种方法是将其作为pthreadWithMalloc
的返回值返回。我仅使用参数方法来说明不同类型的参数。