C中的高效多线程

时间:2017-04-02 20:58:13

标签: c multithreading pthreads

我目前正处于用C编写多线程程序的入门阶段。我理解如何使用完全独立的函数创建单独的线程,但我想了解该领域的程序员如何分解单个任务多线程的优点。我已经完成了几个同步单独线程的练习,但是在分解单个任务并使用多个线程更快时更好。在解决这些类型的问题时,我真的很感激一些智慧,并解释 为什么你会以特定的方式攻击问题。

作为一个例子,让我们说这是我试图用多线程解决的任务。 [它将两个矩阵相乘以创建具有nxp维度的c矩阵。]并且还可以说我们可以输入我们想要在1和t之间运行的线程数(即使线程中没有显着的性能差异> = 4)所以很明显如何攻击它。

 for (i = 0; i < n; i++){
     for (j = 0; j < p; j++){
         c[i][j] = 0;
         for (k = 0; k < m; k++){
             c[i][j] += a[i][k] * b[k][j];
         }
      }
  }

我的第一个想法是根据线程数基本划分每个循环。因此,对于 t 线程,

 for (i = 0; i < n / t; i++){
     for (j = 0; j < p / t; j++){
         c[i][j] = 0;
         for (k = 0; k < m / t; k++){
             c[i][j] += a[i][k] * b[k][j];
         }
      }
  }

然后将它们与信号量同步。但是,这必须将问题的每个部分分成不重叠或错过任何矩阵的t-内聚线程。这似乎有点多,我感觉有更好的方法来攻击它。你们会怎么做呢?

4 个答案:

答案 0 :(得分:1)

并行计算(OpenCL和矢量化)是在同一对象上执行多个任务的最佳方式。也许多线程的最佳用法示例之一是典型的“客户端 - 服务器聊天通信和I / O”。 MT服务器比多进程服务器效率更高,因为每次通信操作的成本都不足以由单个进程处理。

如果我考虑你的矩阵问题,我会通过使用GPU功能和OpenCL并行计算来实现它,因为矩阵中的每个元素都可以同时处理。

Here是使用OpenCL

添加矩阵的示例

如果我必须使用线程,我将通过创建n个线程来解决问题(其中n是CPU的物理(甚至逻辑)核心的数量,并将矩阵的计算除以n部分,就像您一样。显然,信号量处理是互斥的。请注意,通过使用指针算法,矩阵将受到线程的攻击。<​​/ p>

编辑:请注意,多线程解决方案只有在CPU是多核的情况下才能有效工作,在单核CPU的情况下,算术多线程操作比单线程解决方案更有效。

如果这不能回答您的问题,请更准确地了解您的需求。

答案 1 :(得分:1)

有m个操作涉及将左矩阵的一行乘以右矩阵的列。对于t个线程,每个线程可以执行m / t操作。如果m不是t的倍数,则决定如何拆分工作。使用m / t意味着最后一个线程做得更多,使用(m + t-1)/ t表示最后一个线程执行的工作较少,或者对某些线程和(m / t)操作使用(m / t)+1运算在其余的线程上。

这可能不是多线程的好例子,但至少你可以了解这个概念。

这是一个用于合并排序的基于Windows的多线程示例的链接,使用4个线程将性能提高约3倍。我之前认为合并函数中的键循环非常小,以至于进程将受内存限制,但事实证明它是cpu绑定的。

https://codereview.stackexchange.com/questions/148025/multithreaded-bottom-up-merge-sort

答案 2 :(得分:1)

不要试图将其拆分为多个并为每个线程分配一个。首先,这是很多工作。其次,在各种现实条件下表现都非常糟糕。

例如,假设您拥有一台具有四个物理核心和八个虚拟核心的计算机,并且您创建四个线程并为每个四分之一的线程提供工作。如果代码运行时占用了一个物理内核,则两个线程将共享一个物理内核。当两个具有自己的物理核心的“快速”线程完成时,您将拥有三个物理核心,但只有两个线程在运行。呸。

为什么安排事情以便你必须找出最佳分工?这是额外的工作,如果你弄错了,它会让你的代码变慢。不要那样做。

相反,将工作划分为合理的块,并让每个线程使用以下算法:

  1. 还有一大堆工作没有开始吗?
  2. 如果不是,请等待并转到第1步。
  3. 做那么多工作。
  4. 转到第1步。
  5. 因此,您可以将矩阵工作分成大量方便的部分,并创建一个具有合理线程数的池。然后线程可以在任何并发性最佳的情况下运行,只要还有足够的工作要做,所有内核都将保持忙碌。

    换句话说,您正在以错误的方式思考问题并尝试执行调度程序的工作。不要试图将特定的工作分配给特定的线程 - 要做到这一点太难了。

答案 3 :(得分:0)

对于矩阵运算尤其是小矩阵,最好使用SIMD。线程真正进入他们的长期运行任务。对于简短的任务,tge开销变得过高。