为什么我不能在线程执行完后访问线程内分配的数组?

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 值。我只是用参数方式来说明不同类型的参数。