我的用例中需要一个快速线程唤醒机制。所以我写了一个简单的基准来看看信号量是多么好。
#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。这背后的原因是什么?有没有办法以编程方式实现相同的效果,而不是依赖于任务集?
答案 0 :(得分:0)
要使用C代替taskset
程序将您的流程绑定到单个核心,您可以使用sched_setaffinity。
至于为什么一个核心上的两个线程都更快,可能是一些事情: