我无法找出问题所在。我猜测它是我使用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);
}
答案 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
。