使用pthreads_create进行矩阵乘法

时间:2018-02-18 02:37:44

标签: c

我无法找出问题所在。我猜测它是我使用pthread_create的方式还是我乘以索引的方式。有人可以帮我搞清楚吗?我想在我使用的相同结构中。

当我编译它时,它返回

28 23 18
41 34 27
54 45 36
*** stack smashing detected ./matrix terminated
Aborted (core dumped)

代码:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#define M 3
#define K 2
#define N 3 

int A [M][K] ={{1,4},{2,5},{3,6}};
int B [K][N] ={{8,7,6},{5,4,3}};
int C [M][N];

/* structure for passing data to threads */

struct v
{
    int i; /* row */
    int j; /* column */
};

void *matrix_multiplication( void *ptr );  //the thread

int main (int argc, char* argv[]){


    pthread_t workers[M*N];
    int iret1;
    int i = 0;
    int j = 0;
    int a = 1;

    /* We have to create M * N worker threads */
    for (i = 0; i < M ; i++) {
        for (j = 0; j < N; j++){

            struct v *data = (struct v *) malloc (sizeof(struct v));
            data->i = i;
            data->j = j;

            /* Now create the thread passing it data as a parameter */
            iret1 = pthread_create(&workers[a] , NULL , matrix_multiplication, (void  *) data   );

            a++;
            //free(data);

        }
    }

    //wait for all the threads to be finished   
    for (i = 0; i<10 ; i++){
        pthread_join(workers[i], NULL);
    }

    //printing the matrix
    for (i = 0; i < M ; i++) {
        for (j = 0; j < N; j++){
            printf("%d ",C[i][j] );
        }
        printf("\n");
    }   

    return 0;
}

void *matrix_multiplication( void *ptr ){   

    struct v *data = ptr;
    int sum = 0, z;

    for(z=0; z < K; z++){
        sum += A[data->i][z] * B[z][data->j];
    } 

    C[data->i][data->j] = sum;
    printf("%d\n",sum );
    //threads exit
    pthread_exit(0);

}

1 个答案:

答案 0 :(得分:1)

你有几个小错误:

使用

创建线程时
pthread_create(&workers[a], ...

a已经在第一次调用已经1,因为你已经用1初始化了它 表示最后一次pthread_create来电将访问workers 你正在传递指向未定义地址的指针,这是未定义的 行为。您应该使用0初始化a

第二个问题是当您加入主题时:

for (i = 0; i<10 ; i++){
    pthread_join(workers[i], NULL);
}

由于a初始化为1,worker[0]未初始化 线。手册页没有提到传递时会发生什么 未初始化的线程到pthread_join,但我的猜测是它是未定义的行为,很可能是原因 为什么你有段错误。我也会写条件i < M*N,因为 如果您更改任何这些值,您将访问workers 界限。

您无法释放struct v对象的内存,您必须这样做 在join之后。你在那里泄漏记忆。我不认为你甚至需要 要在此处使用malloc,您可以声明M*N的维struct v数组 对象,就像使用pthread_t数组一样。访问阵列时 我使用i*N+j计算两个数组的正确索引。

我使用我的更正和建议修改了您的代码:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#define M 3
#define K 2
#define N 3 

int A [M][K] ={{1,4},{2,5},{3,6}};
int B [K][N] ={{8,7,6},{5,4,3}};
int C [M][N];

/* structure for passing data to threads */

struct v
{
    int i; /* row */
    int j; /* column */
};

void *matrix_multiplication( void *ptr );  //the thread

int main (int argc, char* argv[]){


    pthread_t workers[M*N];
    struct v data[M*N];
    int i = 0;
    int j = 0;

    /* We have to create M * N worker threads */
    for (i = 0; i < M ; i++) {
        for (j = 0; j < N; j++){

            int idx = i*N+j;
            data[idx].i = i;
            data[idx].j = j;

            /* Now create the thread passing it data as a parameter */
            pthread_create(workers + idx, NULL, matrix_multiplication, data+idx);
        }
    }

    //wait for all the threads to be finished   
    for (i = 0; i<M*N ; i++)
        pthread_join(workers[i], NULL);

    //printing the matrix
    for (i = 0; i < M ; i++) {
        for (j = 0; j < N; j++){
            printf("%d ",C[i][j] );
        }
        printf("\n");
    }   


    return 0;
}

void *matrix_multiplication( void *ptr ){   

    struct v *data = ptr;
    int sum = 0, z;

    for(z=0; z < K; z++){
        sum += A[data->i][z] * B[z][data->j];
    } 

    C[data->i][data->j] = sum;
    printf("%d\n",sum );
    pthread_exit(0);
}

如你所见,我没有使用malloc,所以我不必担心释放记忆 然后。当我运行此代码时,我得到:

41
45
18
28
27
34
23
54
36
28 23 18 
41 34 27 
54 45 36 

修改

  

OP在评论部分提出

     

如何释放内存如果我使用malloc作为结构?!

有不同的方法,但第一步是存储指针 malloc返回。现在你没有存储这个价值。

第一个选项是:释放线程中的内存。让我们用你的方式 将值传递给线程:

struct v *data = malloc(sizeof(struct v));
data->i = i;
data->j = j;

/* Now create the thread passing it data as a parameter */
pthread_create(&workers[a] , NULL , matrix_multiplication, data);

每个线程都有一个自己的struct v对象,你永远不会在外面使用它 线程。这就是为什么你可以在线程中做到这一点:

void *matrix_multiplication( void *ptr ) {
    ...
    free(ptr);
    pthread_exit(0);
}

让我们说父进程需要将指针传递给线程。 例如,因为线程在那里写了一些主要的值 线程想要评估。让我们说线程应该计算它们 计算时间。您的struct v可能如下所示:

struct v {
    int i;
    int j;
    double time;
}

线程会计算时间并将其写在data->time上。该 线程可以通过pthread_exit传递给主线程一个指针 如果你的线程可以传递它从主线程获得的相同指针:

#include <time.h>

void *matrix_multiplication( void *ptr ){   

    struct v *data = ptr;
    int sum = 0, z;

    clock_t begin = clock();
    for(z=0; z < K; z++){
        sum += A[data->i][z] * B[z][data->j];
    } 

    C[data->i][data->j] = sum;
    clock_t end = clock();

    data->time = (double)(end - begin) / CLOCKS_PER_SEC;

    //threads exit
    pthread_exit(ptr);
}

现在当你加入线程时,你得到了你传递给线程的指针, 你可以使用那个指针,然后在你不再需要的时候释放它。

double agg_time = 0;
for (i = 0; i<M*N ; i++) {
    struct v *data;
    pthread_join(workers[i], (void**) &data);

    printf("i: %d, j: %d ,time: %lf\n", data->i, data->j, data->time);
    agg_time += data->time;
    free(data);
}
printf("aggregated time: %lf\n", agg_time);

这个的输出是

i: 0, j: 0 ,time: 0.000002
i: 0, j: 1 ,time: 0.000001
i: 0, j: 2 ,time: 0.000002
i: 1, j: 0 ,time: 0.000002
i: 1, j: 1 ,time: 0.000001
i: 1, j: 2 ,time: 0.000001
i: 2, j: 0 ,time: 0.000002
i: 2, j: 1 ,time: 0.000001
i: 2, j: 2 ,time: 0.000014
aggregated time: 0.000026
28 23 18 
41 34 27 
54 45 36 

如果您将malloc ed指针传递给线程,这是我最喜欢的那个。

第三种选择是将malloc数据存储在一个数组中并在之后释放它 加入。

int main(void)
{
    ...
    struct v *data[M*N];

    ...

    for (i = 0; i < M ; i++) {
        for (j = 0; j < N; j++) {
            int idx = i*N+j;
            data[idx] = malloc(sizeof *data[idx]);

            data[idx]->i = i;
            data[idx]->j = j;

            pthread_create(workers + idx, NULL, matrix_multiplication, data[idx]);
        }
    }

    // do the join
    for (i = 0; i<M*N ; i++){
        pthread_join(workers[i], NULL);
    }

    // do the free
    for(int i = 0; i < M*N; ++i)
        free(data[i]);
}

我不太喜欢这个版本,因为它使代码更大,你需要 检查malloc是否没有返回NULL(我已经省略了此测试)并且 失败时的错误处理策略。这对我来说是件好事 第一个代码,你不做malloc,你不必担心free。然而 如果你需要将一个已分配的内存块传递给线程,我就做了 上面,线程将指针返回给主线程 pthread_exit