「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;
}
複製代碼