多线程矩阵乘法

我正在编写一个使用线程级并行执行N X N矩阵乘法的代码。 得到C = A X B, 首先,我将矩阵B,分割矩阵转换成块。 一个线程从A和B中获取一个块并将它们相乘, 然后将结果添加到C中的相应块。 使用malloc()在堆内存中分配所有矩阵。 但问题是,对于相同的输入, 答案有时是不正确的,有时是正确的。 我不太确定为什么会发生这种情况,但我想代码需要在线程安全性方面进行改进。 我发布了我的部分代码。 块是行和列中的块数,即N /块大小。 所以线程的总数是块^ 3。
while (thread_loaded < total_thread)
 {
  if (thread_count < MAX_THREAD)
  {
   p[thread_loaded].idx = thread_idx;
   p[thread_loaded].matinfo = &mi;   
   threads[thread_loaded] = CreateThread(NULL, 0, matmul_tlp, &p[thread_loaded], 0, &threadid[thread_loaded]);
   if (threads[thread_loaded] != NULL)
   {     
    thread_loaded++;
    thread_count++;
    thread_idx += blocks;
    if (thread_idx >= total_thread)
     thread_idx = (thread_idx % total_thread) + 1;
   }          
  }
 }
对于线程函数,
int i, j, k;  
param* p = (param*)arg; 

int blocks = BLOCKS;
int block_size = BLOCK_SIZE;
int Ar = p->idx / (blocks * blocks); 
int Ac = p->idx % blocks;
int Br = (p->idx / blocks) % blocks; 
int Bc = p->idx % blocks;
int Cr = p->idx / (blocks * blocks);
int Cc = (p->idx % (blocks * blocks)) / blocks;

double** A = p->matinfo->A;
double** B = p->matinfo->B;
double** C = p->matinfo->C;


DWORD res = WaitForSingleObject(mutex[Cr * blocks + Cc], INFINITE);
if (res != WAIT_OBJECT_0)
 perror("cannot acquire mutex.");


for (i = 0; i < block_size; i++)
{
 for (j = 0; j < block_size; j++)
 {
  for (k = 0; k < block_size; k++)
  {
   C[Cr * block_size + i][Cc * block_size + j] +=
    A[Ar * block_size + i][Ac * block_size + k] *
    B[Br * block_size + j][Bc * block_size + k];
  }
 }
}


ReleaseMutex(mutex[Cr * blocks + Cc]);


thread_count--;
return NULL;
如果有人能找到一个洞,我们将不胜感激。 :)     
已邀请:
在线程函数中有两个共享值。 C矩阵和thread_count变量。我没有看到C矩阵如何同步有什么问题,但值得仔细检查以确保正确计算Cc和Cr值,因为这是你的互斥选择的基础。 最可能的错误来源是thread_count变量,该变量未同步。请记住,a--相当于'a = a - 1,包含一个读操作,后跟一个写操作(它不是原子)。这意味着它很可能在读取和写入之间被抢占,因此变量的某些减少可能会丢失。例如
Thread A reads the value 10 from thread_count.
Thread B reads the value 10 from thread_count.
Thread B writes the value 10-1 into thread_count.
Thread A writes the value 10-1 into thread_count.
thread_count is now equal to 9 when it should be 8.
所以你刚刚丢失了一个信号到线程创建功能。这可能会导致算法在丢失减量时以越来越少的线程运行。可悲的是,除非我错过了什么,否则我不认为它解释了为什么你会得到不好的结果。你的程序运行速度比实际要慢。 解决这个问题的最简单方法是使用专门针对这些类型情况的条件变量,并避免您在此处遇到的丢失唤醒问题。 顺便说一下,创建线程通常是一个相当昂贵的操作,因此线程池比创建和销毁大量线程更可取。如果线程池比必要的更复杂,那么可以使用条件变量使线程在完成当前任务后等待新任务。 编辑:我写的解决方案有点太快,我最终混淆了两个不同的问题。 首先,您要在线程创建函数和计算函数中同步对thread_count变量的访问。要做到这一点,您可以使用互斥锁,也可以使用InterlockedDecrement,InterlockedIncrement等原子操作数(我希望这些是正确的Windows等价物)。请注意,虽然在这种情况下我没有看到使用原子操作数的任何问题,但它们并不像看起来那么简单。在使用它们之前,请确保完全理解它们。 第二个问题是,在等待其中一个线程完成时,您正在创建线程创建函数。您可以通过使用条件变量在主计算完成后发出信号来避免这种情况。这样你就不会无缘无故地占用处理器时间。 还有一件事,确保你的thread_count变量被声明为volatile,以向编译器指示它在函数中读取和写入的顺序很重要。否则,编译器可以自由地重新排序操作以提高性能。     
请注意,矩阵乘法有助于以非阻塞方式使用多个线程。要记住的是c [i,j] =对于所有k,求和[i,k] * b [k,j]。此操作是自包含的,并且在您的线程代码中不需要同步。起始线程只需要对包含a,b,c矩阵的类或结构的引用,需要同步的条目容器以及用于同步条目容器的互斥锁。访问此条目容器需要使用互斥锁来访问它,但其他所有内容都不需要任何互斥锁调用。条目容器中的每个条目都将包含接下来要计算的c矩阵的当前行和列。然后,每个线程将查询条目容器,直到容器为空。唯一真正的任务是在创建/启动线程之前生成条目容器。     

要回复问题请先登录注册