C++中的多线程矩阵乘法

Posted

技术标签:

【中文标题】C++中的多线程矩阵乘法【英文标题】:Multithreaded matrix multiplication in C++ 【发布时间】:2012-10-29 07:56:24 【问题描述】:

我在使用这个并行矩阵乘法代码时遇到了问题,在尝试访问我的结构中的数据成员时一直出错。

这是我的主要功能:

struct arg_struct

  int* arg1;
  int* arg2;
  int arg3;
  int* arg4;
;


int main()

  pthread_t allthreads[4];
  int A [N*N];
  int B [N*N];
  int C [N*N];
  randomMatrix(A);
  randomMatrix(B);
  printMatrix(A);
  printMatrix(B);
  struct arg_struct *args = (arg_struct*)malloc(sizeof(struct arg_struct));
  args.arg1 = A;
  args.arg2 = B;
  int x;
  for (int i = 0; i < 4; i++)
  
     args.arg3 = i;
     args.arg4 = C;
     x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)args); 
     if(x!=0)
     exit(1);
  

  return 0;

以及从另一个 C 文件中使用的 matrixMultiplication 方法:

void *matrixMultiplication(void* arguments)

     struct arg_struct* args = (struct arg_struct*) arguments;
     int block = args.arg3;
     int* A = args.arg1;
     int* B = args.arg2;
     int* C = args->arg4;
     free(args);
     int startln = getStartLineFromBlock(block);
     int startcol = getStartColumnFromBlock(block);
     for (int i = startln; i < startln+(N/2); i++)
     
        for (int j = startcol; j < startcol+(N/2); j++)
        
          setMatrixValue(C,0,i,j);
          for(int k = 0; k < N; k++)
          
             C[i*N+j] += (getMatrixValue(A,i,k) * getMatrixValue(B,k,j));
             usleep(1);
           
        
     

我遇到的另一个错误是在创建线程时:“从 'void ()(int, int*, int, int*)' 到 'void* () 的无效转换(void)' [-fpermissive] "

谁能告诉我我做错了什么?

【问题讨论】:

您遇到的第一个错误是什么? 这是C,除了main函数 另一个错误,在哪里你得到它了吗?换句话说,你能指出你在哪里得到了那个错误吗? 这是另一条错误消息:“parallel.c:41:82: error: invalid conversion from 'void ()(int, int*, int, int* )' 到 'void* ()(void)' [-fpermissive] /usr/include/pthread.h:225:12: 错误:初始化参数 3 of 'int pthread_create(pthread_t*, const pthread_attr_t*, void* ()(void), void*)' [-fpermissive] " 和线程创建在同一行 您在该行之前声明了另一个名为matrixMultiplication 的函数吗?如果是这样,请重命名您的 void *matricMultiplication(void*) 函数以避免冲突 【参考方案1】:

首先你将 C 和 C++ 混合得非常糟糕,要么使用纯 C 要么使用 C++,在 C++ 中你可以简单地使用 newdelete

但是你的错误原因是你在一个地方分配arg_struct 并在4个线程中释放它。你应该为每个线程分配一个arg_struct

【讨论】:

他也在各个线程完成之前从main返回。他的代码块包含指向局部变量的指针,一旦他从函数返回,局部变量就会悬空。【参考方案2】:

Big Boss 在他发现问题的意义上是正确的,但要添加/增强他所做的回复。

选项 1: 只需在循环中创建一个 arg_struct 并设置成员,然后将其传递:

for(...)

    struct arg_struct *args = (arg_struct*)malloc(sizeof(struct arg_struct)); 
    args->arg1 = A;
    args->arg2 = B;    //set up args as now...
    ...
    x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)args);
    ....

在线程中保留free 调用,但现在您可以直接使用传递的结构,而不是在线程中创建局部变量。

选项 2: 看起来您无论如何都想将结构中的参数复制到线程中,因此您不需要动态分配。

只需创建一个 arg_struct 并设置成员,然后将其传递:

arg_struct args;
//set up args as now...
for(...)

   ...
   x = pthread_create(&allthreads[i], NULL, &matrixMultiplication, (void*)&args);

然后删除free 调用。

但是,正如 James 指出的那样,您需要在结构上的线程/父级中进行同步,以确保它没有被更改。这将意味着 Mutex 或其他一些机制。因此,将分配转移到 for 循环可能更容易开始。

第 2 部分:

我正在 Windows 上工作(所以我目前无法进行实验),但 pthread_create 参数 3 指的是定义为 void* matrixMultiplication( void* ); 的线程函数 matrixMultiplication - 它看起来对我来说是正确的(签名明智)来自男人在线页面,void* fn (void* )

对于您的第二个错误,我想我将不得不听从其他人的意见。将此帖子设为社区 wiki 条目,因此如果需要,可以将答案放入其中。

【讨论】:

非常感谢 John,它解决了我的数据成员访问问题,但我仍然收到 OP 中提到的第二条错误消息:“parallel.c:41:82: error: invalid conversion from 'void ()(int, int*, int, int*)' 到 'void* ()(void)' [-fpermissive] /usr/include/pthread.h :225:12: 错误:初始化参数 3'int pthread_create(pthread_t*, const pthread_attr_t*, void* ()(void), void*)' [-fpermissive] " 如果您要为所有线程使用相同的args,您必须添加同步代码以确保刚刚启动的线程在您更改之前已完成它命令开始下一个线程。 (如果您使用boost::thread 并按值传递,则为您完成。)【参考方案3】:

我不清楚你想做什么。你开始一些线程, 然后你在得到任何东西之前从main(退出进程)返回 他们的结果。

在这种情况下,我可能直接使用任何动态分配。 (我会使用std::vector 作为矩阵,它会使用动态 内部分配。)没有理由动态分配 arg_struct,因为它可以安全地复制。当然,你必须 等到每个线程都成功提取了它的数据之前 循环构造下一个线程。这通常会使用 一个条件:新线程一旦有条件就会解除阻塞 从arg_struct 中提取参数(或者更好的是,您可以 使用boost::thread,它会为你完成这部分)。或者,你 可以使用arg_struct 的数组,但绝对没有理由 动态分配它们。 (如果由于某种原因您不能使用 std::vector 用于 ABC,您想要分配这些 动态地,以避免堆栈溢出的任何风险。但 std::vector 是一个更好的解决方案。)

最后,当然,您必须等待所有线程完成 在离开之前main。否则,线程将继续工作 不再存在的数据。在这种情况下,您应该 pthread_join 退出 main 之前的所有线程。想必, 你也想对乘法的结果做点什么, 但无论如何,在所有线程完成之前退出main 访问矩阵将导致未定义的行为。

【讨论】:

以上是关于C++中的多线程矩阵乘法的主要内容,如果未能解决你的问题,请参考以下文章

numpy/pandas矩阵乘法的多线程?

C++ openMP 并行矩阵乘法

稀疏矩阵与密集矩阵乘法 C++ Tensorflow

使用 CUDA 进行矩阵乘法:2D 块与 1D 块

C++ 乘法大矩阵

C++ 矩阵乘法向量 out_of_range 异常