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

问题描述 投票:0回答:1

我正在使用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()上声明的变量中。我只想了解更好的情况。

c pthreads malloc
1个回答
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的返回值返回。我只使用参数方法来说明不同类型的参数。

© www.soinside.com 2019 - 2024. All rights reserved.