为什么我不能在线程执行完后访问线程内分配的数组?
Why can't I access an array allocated inside a thread after this thread has finished executing?
我正在使用 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()
上声明的变量中。我只是想更好地了解发生了什么。
threadWithMalloc
永远不会将分配的存储地址发送回其调用者或主线程。它是用参数vector
声明的,然后给vector
赋值:
vector = malloc(sizeof(int) * N);
这一切所做的只是改变参数的值,这对函数来说是有效的。更改函数中的参数不会更改在主例程中传递的参数。因此,在主例程中pointer_vector[1]
没有改变。
要解决这个问题,让我们首先修复例程声明。 pthread_create
采用类型 void *(*)(void *)
的参数,它是指向采用 void *
参数并 returning void *
结果的例程的指针。因此,线程例程应声明为采用 void *
参数和 returning 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 *
的指针,这为它提供了 space 的地址,我们希望它在其中存储 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 *
的方法是 return 它作为 pthreadWithMalloc
的 return 值。我只是用参数方式来说明不同类型的参数。
我正在使用 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()
上声明的变量中。我只是想更好地了解发生了什么。
threadWithMalloc
永远不会将分配的存储地址发送回其调用者或主线程。它是用参数vector
声明的,然后给vector
赋值:
vector = malloc(sizeof(int) * N);
这一切所做的只是改变参数的值,这对函数来说是有效的。更改函数中的参数不会更改在主例程中传递的参数。因此,在主例程中pointer_vector[1]
没有改变。
要解决这个问题,让我们首先修复例程声明。 pthread_create
采用类型 void *(*)(void *)
的参数,它是指向采用 void *
参数并 returning void *
结果的例程的指针。因此,线程例程应声明为采用 void *
参数和 returning 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 *
的指针,这为它提供了 space 的地址,我们希望它在其中存储 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 *
的方法是 return 它作为 pthreadWithMalloc
的 return 值。我只是用参数方式来说明不同类型的参数。