比较和交换如何工作

我已经阅读了一些post,说比较和交换保证primefaces性,但是我仍然无法得到它是怎么回事。 以下是比较和交换的通用伪代码:

int CAS(int *ptr,int oldvalue,int newvalue) { int temp = *ptr; if(*ptr == oldvalue) *ptr = newvalue return temp; } 

这如何保证primefaces性? 例如,如果我使用它来实现互斥锁,

 void lock(int *mutex) { while(!CAS(mutex, 0 , 1)); } 

这如何防止2个线程同时获取互斥锁? 任何指针都会非常感激。

“通用伪代码”不是CAS(比较和交换)实现的实际代码。 特殊硬件指令用于激活CPU中的特殊primefaces硬件。 例如,在x86中可以使用LOCK CMPXCHGhttp://en.wikipedia.org/wiki/Compare-and-swap )。

例如,在gcc中,有__sync_val_compare_and_swap()内置 – 它实现特定于硬件的primefacesCAS。 这个操作的描述来自Paul E. McKenney的新精彩书籍( Is Parallel Programming Hard,And,If So,你能做些什么呢? ,2014),第4.3节“primefaces操作”,第31-32页。

如果您想了解更多关于在primefaces操作之上构建更高级别同步并在自动旋转中保存系统免受自旋锁和烧录cpu周期的更多信息,您可以在Linux中阅读有关futex机制的内容。 关于futexes的第一篇论文是Ulute Drepper 2011的Futexes很棘手 ; 另一个是LWN文章http://lwn.net/Articles/360699/ (历史性的文章是Fuss,Futexes和Furwocks:Linux中的Fast Userland Locking ,2002)

Ulrich描述的互斥锁仅使用“快速路径”的primefaces操作(当互斥锁未被锁定且我们的线程是唯一想要锁定它的线程时),但如果互斥锁被锁定,线程将使用futex进入hibernate状态( FUTEX_WAIT …)(它将使用primefaces操作标记互斥变量,以通知解锁线程“有人在这个互斥锁上等待”,因此解锁器将知道他必须使用futex唤醒它们(FUTEX_WAKE,.. 。)

它如何防止两个线程获取锁? 好吧,一旦任何一个线程成功, *mutex将为1 ,因此任何其他线程的CAS将失败(因为它被调用期望值0 )。 通过在*mutex存储0来释放锁定。

请注意,这是CAS的一种奇怪用法,因为它基本上要求违反ABA。 通常你只使用普通的primefaces交换:

 while (exchange(mutex, 1) == 1) { /* spin */ } // critical section *mutex = 0; // atomically 

或者,如果您想要稍微复杂一点并存储有关哪个线程具有锁定的信息,您可以使用atomic-fetch-and-add进行操作(例如,参见Linux内核自旋锁代码)。