使用taskset -c

时间:2016-05-01 23:41:14

标签: linux multithreading

我的用例中需要一个快速线程唤醒机制。所以我写了一个简单的基准来看看信号量是多么好。

#define PCALL(f)  \
  do {            \
    if (f == -1) { \
      perror(#f); \
      abort();    \
    }             \
  } while (0)

bool should_stop = false;

namespace semaphore_pthread{

struct Arg {
  sem_t start, stop;
} sems;

inline void SemInit(sem_t* sem) { PCALL(sem_init(sem, 0, 0)); }

inline void SemPost(sem_t* sem) { PCALL(sem_post(sem)); }

inline void SemWait(sem_t* sem) {
  int ret;
  do {
    ret = sem_wait(sem);
  } while (ret == -1 && errno == EINTR);
}

inline void SemDestroy(sem_t* sem) { PCALL(sem_destroy(sem));  }

void* StopperFunc(void *arg) {
  while (true) {
    SemWait(&sems.start);
    if (should_stop) break;
    SemPost(&sems.stop);
  }
  return nullptr;
}

int num_iters;
void* StarterFunc(void* arg) {
  pthread_t stopper;
  PCALL(pthread_create(&stopper, nullptr, &StopperFunc, nullptr));
  StartBenchmarkTiming();
  for (int i = 0; i < num_iters; ++i) {
    SemPost(&sems.start);
    SemWait(&sems.stop);
  }
  StopBenchmarkTiming();
  should_stop = true;
  SemPost(&sems.start);
  PCALL(pthread_join(stopper, nullptr));
  return nullptr;
}

void BM_Sem(int iters) {
  num_iters = iters;
  pthread_t starter;
  PCALL(pthread_create(&starter, nullptr, &StarterFunc, nullptr));
  PCALL(pthread_join(starter, nullptr));
}

只有两个线程像打醒一样做乒乓球。每次迭代都包括两次唤醒。

在我的机器上(Intel(R)Xeon(R)CPU E5-1650 0 @ 3.20GHz),每次迭代大约需要5us。我也尝试过eventfd和futex,但是他们也提供了类似的结果。但是,如果使用taskset -c 1(所有线程在CPU 1中运行),则只需1.5 us。这背后的原因是什么?有没有办法以编程方式实现相同的效果,而不是依赖于任务集?

1 个答案:

答案 0 :(得分:0)

要使用C代替taskset程序将您的流程绑定到单个核心,您可以使用sched_setaffinity

至于为什么一个核心上的两个线程都更快,可能是一些事情:

  1. 两个独立的核心具有单独的缓存,需要复制一些相同的信息。
  2. 系统上的其他任务可能是竞争,弄脏缓存。
  3. 两个内核可能位于两个独立的物理处理器上,需要进行插槽间通信。
  4. 当只有一个核心处于活动状态时,它更有可能进入&#34; turbo&#34;英特尔处理器上的模式,而不是睡眠模式。