“phaser”是一个同步原语,它容许线程知道全部其余线程已经经过执行中的某个点,但没有阻塞任何这些线程。 在调用者想要在解除分配以前保证共享资源再也不可见的状况下,它很是有用。缓存
任何数量的线程均可以进入和退出由移相器保护的“关键区域”; 他们使用例程退出phaser_enter和phaser_exit。 这些功能是非等待,非阻塞,彻底可重入,绝对可靠和异步信号安全。安全
另外一个线程(一次最多一个)能够同时调用phaser_drain。 此函数会阻塞全部线程在调用phaser_drain以前进入受监控区域 相应的调用phaser_exit退出该区域。bash
phaser_enter和phaser_exit是异步信号安全的而且彻底可重入,使得它们很是适用于其余同步原语可能很麻烦的信号处理程序。并发
Phaser很是重量级。 phaser_enter和phaser_exit是常见状况下的原子增量和原子减量。 在Intel i7-4600U上,phaser_enter和phaser_exit对在大约28个周期内完成。 若是phaser_drain同时运行,那么成本大约会翻倍。异步
虽然移相器自己能够充分执行,但它只占用一个缓存行,可能会在严重争用的状况下损害性能。 经过使用多个相位器(每一个相位器位于不一样的高速缓存线上),调用者能够在这种状况下将性能提升两倍。 进入关键部分的线程能够根据CPU亲和性选择移相器,而且想要在全部读取器上同步的线程能够依次调用每一个高速缓存行上的phaser_drain。ide
Phaser依赖于操做系统提供某种等待地址功能。 在Linux上,咱们直接使用futex。 在Windows上,可使用WaitOnAddress。 在FreeBSD上,umtx应该能够工做; 在iOS上,内核的psynch_cvwait psynch_cvsignal就足够了。函数
请注意,worker_threads()不执行重量级同步,而且对worker_threads()和atomically_increment_array()的任何数量的调用均可以并发运行。oop
std::vector<int>* g_array;
pthread_mutex_t array_phaser_lock = PTHREAD_MUTEX_INITIALIZER;
phaser_t array_phaser;
void init()
{
pthread_mutex_init(&array_phaser_lock);
phaser_init(&array_phaser);
}
void worker_threads()
{
phaser_phase phase;
for(;;) {
phase = phaser_enter(array_phaser);
operate_on_array(array);
phaser_exit(array_phaser, phase);
}
}
void atomically_increment_array()
{
std::vector<int>* old_array;
std::vector<int>* new_array;
bool success;
do {
phaser_enter(array_phaser);
old_array = __atomic_load_n(&g_array, __ATOMIC_ACQUIRE);
// NB: in real code, the std::vector constructor can throw,
// and calling code should take care to exit the phaser
// critical section if it does.
new_array = new std::vector<int>(*old_array);
for(auto it = new_array->begin(); it != new_array->end(); ++it) {
*it += 1;
}
// Important to use __ATOMIC_RELEASE on the success path:
// other threads must see only fully-constructed vector.
success =
__atomic_compare_exchange_n(
&g_array,
&old_array,
new_array,
true // weak: we loop anyway,
__ATOMIC_RELEASE,
__ATOMIC_RELAXED);
phaser_exit(array_phaser);
if(!success) {
* Someone else beat us to the increment, so try again.
delete new_array;
}
} while(!success);
// We exclusively own the old array. Wait for pending readers
// to finish.
pthread_mutex_lock(&array_phaser_lock);
phaser_drain(array_phaser);
pthread_mutex_unlock(&array_phaser_lock);
// Now we know that nobody is using old_array: all
// references to array occur inside a phaser critical
// section, and the call to phaser_drain ensured that
// all critical sections that began while g_array still
// pointed at old_array have now terminated.
delete old_array;
}
复制代码