四核Linux:单个可执行文件,4个进程



我有4个可执行程序,它们可以执行一些非常复杂的任务,仅这些程序中的每一个就可能占用四核CPU的单核功率的近100%,因此几乎占CPU总功率的25%。由于所有这些程序都使用无法在多个进程之间共享的硬件资源,因此我希望运行一个可执行文件,该可执行文件会产生3个子进程,而这些子进程又会占用其他三个核心。我在Linux上,使用的是C++11。大多数复杂的代码都在自己的类中运行,最难的部分在我通常称为Process()的函数中运行,所以我有4个对象,每个对象都有自己的Process(),当运行时,它占用100%的单个核心。

我尝试过使用OpenMP,但我认为这不是最好的解决方案,因为我无法控制CPU亲和力。另外,使用std::thread也不是一个好主意,因为线程继承了主进程的CPU相关性。在Linux中,我认为我可以用fork()来实现这一点,但我不知道整个结构是如何构建的。

这可能与我的另一个问题有关,这个问题部分没有得到回答,可能是因为我尝试了错误的方法,这种方法在某些情况下有效,但在我的情况下无效。

伪代码的一个例子可能是:

int main()
{
  // ...init everything...
  // This alone takes 100% of a single core
  float out1 = object1->Process(); 
  // This should be spawned as a child process running on another core
  float out2 = object2->Process();
  // on another core...
  float out3 ...
  // yet another core...
  float out4 ...
  // This should still run in the parent process
  float total_output = out1 + out2 + out3 + out4;
}

您可以使用std::thread,它是pthread_create()的前端。然后从线程本身设置它与sched_setaffinity()的亲和性。

正如你所问,这里有一个工作存根:

#include <sched.h>
#include <thread>
#include <list>
void thread_func(int cpu_index) {
  cpu_set_t cpuSet;
  CPU_ZERO(&cpuSet);
  CPU_SET(cpu_index, &cpuSet);
  sched_setaffinity(0, sizeof( cpu_set_t), &cpuSet);
  /* the rest of the thread body here */
}
using namespace std;
int main(int argc, char **argv)  {
  if (argc != 2) exit(1);
  int n_cpus = atoi(argv[1]);
  list< shared_ptr< thread > > lot;
  for (int i=0; i<n_cpus; ++i) {
    lot.push_back( shared_ptr<thread>(new thread(thread_func, i)));
  }
  for(auto tptr = lot.begin(); tptr != lot.end(); ++tptr) {
    (*tptr)->join();
  }
}

请注意,为了获得最佳行为,如果您希望您的代码也在多处理器上进行优化,那么每个线程在线程体中初始化其内存(即构造其对象)是很重要的,因为如果您在NUMA系统上工作,则使用内存页在靠近CPU的内存上分配内存页。

例如,你可以看看这个博客。

然而,在您的特定情况下,这并不是一个问题,因为您处理的是一个单处理器系统,或者更具体地说,是一个只有一个numa节点的系统(许多当前的AMD处理器确实包含两个numa节点,即使是在一个物理包中),并且所有的内存组都连接在那里。

在这种情况下使用sched_setaffinity()的最终效果只是将每个线程固定到一个特定的核心。

您不必编写任何程序。命令taskset更改当前正在运行的进程的CPU相关性,或者为新进程创建并设置它。

运行一个生成其他程序的可执行文件与直接执行程序没有什么不同,只是存根中的注释暗示了常见的初始化。

taskset 1 program_for_cpu_0 arg1 arg2 arg3...
taskset 2 program_for_cpu_1 arg1 arg2 arg3...
taskset 4 program_for_cpu_2 arg1 arg2 arg3...
taskset 8 program_for_cpu_3 arg1 arg2 arg3...

我对设置CPU亲和力持怀疑态度。我还没有找到这样做的实际用途(除了满足一些内心的控制需求)。

除非CPU在某些方面不相同,否则不需要将进程限制为特定的CPU。

  1. Linux内核通常将进程保持在同一CPU上,除非它进入对i/o、信号量等的扩展等待
  2. 将进程从一个CPU切换到另一个CPU不会产生任何特定的开销,除非在每个CPU具有本地内存的NUMA配置中。AFAIK,ARM的实现并不能做到这一点
  3. 如果进程应该表现出非CPU绑定行为,那么允许内核调度器灵活地将进程重新分配给现在可用的CPU应该可以提高系统性能。绑定到CPU的进程无法参与资源可用性

最新更新