OpenMP 绑定核跟线程

  for (; i < nthreads; ++i)
    {
      int err;

      start_data->ts.place_partition_off = thr->ts.place_partition_off;
      start_data->ts.place_partition_len = thr->ts.place_partition_len;
      start_data->place = 0;
      if ( (gomp_places_list != NULL, 0))
        {
      switch (bind)
        {
        case omp_proc_bind_true:
        case omp_proc_bind_close:
          if (k == s)
        {
          ++p;
          if (p == (team->prev_ts.place_partition_off
                + team->prev_ts.place_partition_len))
            p = team->prev_ts.place_partition_off;
          k = 1;
          if (i == nthreads - rest)
            s = 1;
        }
          else
        ++k;
          break;
        case omp_proc_bind_master:
          break;
        case omp_proc_bind_spread:
          if (k == 0)
        {
          /* T <= P.  */
          if (p < rest)
            p += s + 1;
          else
            p += s;
          if (p == (team->prev_ts.place_partition_off
                + team->prev_ts.place_partition_len))
            p = team->prev_ts.place_partition_off;
          start_data->ts.place_partition_off = p;
          if (p < rest)
            start_data->ts.place_partition_len = s + 1;
          else
            start_data->ts.place_partition_len = s;
        }
          else
        {
          /* T > P.  */
          if (k == s)
            {
              ++p;
              if (p == (team->prev_ts.place_partition_off
                + team->prev_ts.place_partition_len))
            p = team->prev_ts.place_partition_off;
              k = 1;
              if (i == nthreads - rest)
            s = 1;
            }
          else
            ++k;
          start_data->ts.place_partition_off = p;
          start_data->ts.place_partition_len = 1;
        }
          break;
        }
      start_data->place = p + 1;
      if (affinity_thr != NULL && pool->threads[i] != NULL)
        continue;
      gomp_init_thread_affinity (attr, p);
    }

这段代码是 gomp_team_start() 中为新线程进行 place 绑定(affinity placement) 的关键部分。它的核心作用是:根据 OpenMP 的 proc_bind 策略,为每个新线程分配合适的 CPU 运行位置(place),并初始化线程亲和性(thread affinity)


✅ 主要功能概览

对于每个线程 i ∈ [old_threads_used, nthreads)

  1. 默认继承 place_partition 信息

    start_data->ts.place_partition_off = thr->ts.place_partition_off;
    start_data->ts.place_partition_len = thr->ts.place_partition_len;
    start_data->place = 0;
  2. 如果启用了 place 列表(gomp_places_list != NULL,则根据 proc_bind 策略重新计算 place 绑定:

    switch (bind) {
     case omp_proc_bind_true:
     case omp_proc_bind_close:
     case omp_proc_bind_master:
     case omp_proc_bind_spread:
  3. 计算当前线程应绑定的 place 编号 p,并更新其线程结构体中的 place_partition_off/len

  4. 最终调用 gomp_init_thread_affinity(attr, p) 完成线程 affinity 设置


🔧 各个 bind 策略解释

策略名 行为说明
omp_proc_bind_master 所有线程使用与 master 相同的 place,默认不更改 p
omp_proc_bind_true / close 尽量将线程绑定到紧密相邻的 place,通过 ks 控制周期性换组。
omp_proc_bind_spread 尽量将线程均匀分布到不同 place,尤其在线程数 > place 数时将 place 拆分为单线程。

🧠 核心变量含义

变量名 含义
p 当前 place 编号,表示线程应该被分配的 CPU core group 索引
k 当前在某个 place 上放了几个线程
s 每个 place 应分配多少线程(基本值)
rest 多余线程个数,用于在部分 place 上分配 s+1 个线程
start_data->place 最终分配给线程的逻辑编号(place id + 1)

✅ 特别判断:是否需要创建新线程

if (affinity_thr != NULL && pool->threads[i] != NULL)
  continue;

如果 affinity 线程池中已经有复用线程,就跳过 pthread_create,表示线程池线程可被复用,不需要新建。


🔚 总结一句话

这一段代码的主要作用是:根据不同的 proc_bind 策略计算每个线程应绑定的 CPU place,并调用亲和性设置函数实现线程绑定,从而实现 OpenMP 的线程拓扑感知调度。