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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么我不能在这个线程完成执行后访问线程内部分配的数组?相关的知识,希望对你有一定的参考价值。

我正在使用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 *参数并返回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的返回值返回。我只使用参数方法来说明不同类型的参数。

以上是关于为什么我不能在这个线程完成执行后访问线程内部分配的数组?的主要内容,如果未能解决你的问题,请参考以下文章

线程局部存储的Win32实现

python线程同步

Java基础总结--多线程总结1

runloop

什么是Java多线程编程?

Fork/Join框架