【问题标题】:Matrix Multiply with Threads (each thread does single multiply)矩阵乘以线程(每个线程进行单次乘法)
【发布时间】:2013-03-16 01:18:43
【问题描述】:

我希望使用线程进行矩阵乘法,其中每个线程执行一次乘法,然后主线程将所有结果相加并将它们放置在最终矩阵中的适当位置(在其他线程具有退出)。

我尝试这样做的方法是创建一个包含每个线程结果的单行数组。然后我会遍历数组并将结果添加到最终矩阵中。

例如:如果你有矩阵:

A = [{1,4}, {2,5}, {3,6}] B = [{8,7,6}, {5,4,3}]

然后我想要一个包含 [8, 20, 7, 16, 6, 12, 16 等] 的数组 然后,我将遍历数组,将每 2 个数字相加并将它们放入我的最终数组中。

这是一个硬件分配,所以我不是在寻找确切的代码,而是关于如何将结果正确存储在数组中的一些逻辑。我正在为如何跟踪我在每个矩阵中的位置而苦苦挣扎,这样我就不会错过任何数字。

谢谢。

EDIT2:忘了提到每个乘法必须有一个线程才能完成。就上面的例子来说,有 18 个线程,每个线程都在做自己的计算。

编辑:我目前正在使用此代码作为基础。

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

#define M 3
#define K 2
#define N 3
#define NUM_THREADS 10

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

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

void *runner(void *param); /* the thread */

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

   int i,j, count = 0;
   for(i = 0; i < M; i++) {
      for(j = 0; j < N; j++) {
         //Assign a row and column for each thread
         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 */
         pthread_t tid;       //Thread ID
         pthread_attr_t attr; //Set of thread attributes
         //Get the default attributes
         pthread_attr_init(&attr);
         //Create the thread
         pthread_create(&tid,&attr,runner,data);
         //Make sure the parent waits for all thread to complete
         pthread_join(tid, NULL);
         count++;
      }
   }

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

//The thread will begin control in this function
void *runner(void *param) {
   struct v *data = param; // the structure that holds our data
   int n, sum = 0; //the counter and sum

   //Row multiplied by column
   for(n = 0; n< K; n++){
      sum += A[data->i][n] * B[n][data->j];
   }
   //assign the sum to its coordinate
   C[data->i][data->j] = sum;

   //Exit the thread
   pthread_exit(0);
}

来源:http://macboypro.wordpress.com/2009/05/20/matrix-multiplication-in-c-using-pthreads-on-linux/

【问题讨论】:

  • 这在之前已经完成了大约十万次。通过确定机器上的 CPU 核心数 C,确定需要多少行 x 列向量乘法,将后者除以前者(大致),你会好多并将其发送到C 线程以相互独立处理。任何模数(最多 C-1 的额外向量)作为额外乘法发送到第一系列线程。您将很难获得更有效和更简单的算法,尤其是考虑到绝对不需要任何锁定。
  • 对不起,我不清楚。根据分配,必须完成的每个乘法运算都必须有 1 个线程。这意味着,对于我给出的示例矩阵,将有 18 个线程进行 18 次乘法运算。它并不意味着高效。这只是一个硬件练习。
  • 是的,我想这一定只是一个练习。当你使用A[500][800] x B[800][1000] 之类的东西时,这个概念会很快退化。它越大,您在开始加入线程时花费的时间就越多,而您可能只是在进行乘法运算。呃,好吧。祝你好运!
  • 如果矩阵足够大,您可能还想研究 Strassen algorithm 的矩阵乘法 - 以及额外的功劳?

标签: c multithreading pthreads matrix-multiplication


【解决方案1】:

您需要存储M * K * N element-wise 产品。这个想法大概是线程将全部并行运行,或者至少能够并行​​运行,因此每个线程都需要自己独特的适当类型的存储位置。一个直接的方法是创建一个包含这么多元素的数组......但是元素类型是什么?

每个线程不仅需要知道将结果存储在哪里,还需要知道要执行哪个乘法运算。所有这些信息都需要通过void * 类型的单个参数来传达。然后,通常会创建一种适合保存一个线程所需的所有数据的结构类型,为每个线程创建该结构类型的实例,并将指针传递给这些结构。那么听起来你想要一个结构数组。

可以通过多种方式处理细节,但对我来说最自然的一种是为这两个因素提供结构成员,以及存储产品的成员。然后我会让主线程声明一个此类结构的 3D 数组(如果所需的总数很小),或者动态分配一个。例如,

struct multiplication {
    // written by the main thread; read by the compute thread:
    int factor1;
    int factor2;

    // written by the compute thread; read by the main thread:
    int product;
} partial_result[M][K][N];

如何围绕它编写代码留作打算做的练习。

【讨论】:

    【解决方案2】:

    不确定你需要调度多少线程,我也不确定你以后是否会使用 join 来接收它们。我猜你在这里是 C 语言,所以我会使用线程 id 作为跟踪要处理的行的一种方式......类似于:

    #define NUM_THREADS 64
    /*
     * struct to pass parameters to a dispatched thread 
     */
    typedef struct {
      int   value;     /* thread number */
      char  somechar[128];   /* char data passed to thread */
      unsigned long ret;
      struct foo *row;
    } thread_parm_t;
    

    我猜每个线程都会在指针 *row 中获取其行数据,该指针具有一些定义的类型 foo。一堆整数或浮点数甚至复杂类型。无论你需要传递给线程。

    /*
     * the thread to actually crunch the row data
     */
    void *thr_rowcrunch( void *parm );
    
    pthread_t tid[NUM_THREADS]; /* POSIX array of thread IDs */
    

    然后在你的主代码段中类似:

    thread_parm_t *parm=NULL;
    

    然后用类似这样的方式调度线程:

    for ( i = 0; i < NUM_THREADS; i++) {
        parm = malloc(sizeof(thread_parm_t));
        parm->value = i;
        strcpy(parm->somechar, char_data_to-pass );
        fill_in_row ( parm->row, my_row_data );
        pthread_create(&tid[i], NULL, thr_insert, (void *)parm);
    }
    

    然后:

    for ( i = 0; i < NUM_THREADS; i++)
        pthread_join(tid[i], NULL);
    

    然而,真正的工作需要在接收行数据的 thr_rowcrunch( void *parm ) 中完成,然后每个线程知道它自己的线程号。你在那个分派的线程中所做的事情的胆量,但我只能猜测。

    只是想在这里帮忙,不知道这是否清楚。

    【讨论】:

    • 您能分享一下矩阵乘法的实际输入数据吗?即使只是出于我自己的原因,我实际上也对这个问题感兴趣。我想制定一个线程整齐的解决方案,非常值得喝杯咖啡并编写解决方案。
    • 实际输入的数据是可变的。对于赋值,我们需要做一些文件 I/O 来读取矩阵,然后输出结果。与我的问题无关。由于代码不应该取决于矩阵,因此我一直在使用我在原始帖子中给出的示例来尝试让它工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    相关资源
    最近更新 更多