pthread_mutex_lock和pthread_mutex_unlock函数是否调用内存栅栏/屏障指令?或者较低级别的指令如compare_and_swap是否隐式包含内存屏障?
pthread_mutex_lock和pthread_mutex_unlock函数会调用内存屏障/栅栏指令吗?
它们会,线程创建也是一样。
然而需要注意的是,内存屏障有两种类型:编译器和硬件。
编译器屏障只能防止编译器重新排列读写顺序和猜测变量值,但不能防止CPU重新排序。
硬件屏障可以防止CPU重新排序读写操作。完整的内存屏障通常是最慢的指令,大多数时候你只需要具备获取和释放语义的操作(以实现自旋锁和互斥锁)。
在多线程中,你大多数情况下都需要这两种屏障。
任何在此翻译单元中未提供定义(且不是内部函数)的函数都是编译器屏障。pthread_mutex_lock、pthread_mutex_unlock、pthread_create也会发出硬件内存屏障以防止CPU重新排序读写操作。
引自David R. Butenhof的《使用POSIX线程编程》。
Pthreads提供了一些关于内存可见性的基本规则。您可以指望标准的所有实现都遵循这些规则:
当调用pthread_create
时,线程可以看到的任何内存值也可以在新线程启动时被看到。在调用pthread_create
之后写入内存的任何数据可能不会被新线程看到,即使写入发生在线程启动之前。
当一个线程解锁互斥量时,无论是直接解锁还是等待条件变量,该线程可以看到的任何内存值也可以被稍后锁定同一互斥量的任何线程看到。同样,在解锁互斥量之后写入的数据可能不会被锁定互斥量的线程看到,即使写入发生在锁定之前。
当一个线程通过取消、从其启动函数返回或调用pthread_exit
终止时,可以看到的任何内存值也可以被通过调用pthread_join
与已终止线程连接的线程看到。当然,线程终止后写入的数据可能不会被连接的线程看到,即使写入发生在连接之前。
当一个线程发出信号或广播条件变量时,可以看到的任何内存值也可以被该信号或广播唤醒的任何线程看到。同样,在发出信号或广播之后写入的数据可能不会被唤醒的线程看到,即使写入发生在唤醒之前。
compare_and_swap
:POSIX标准中没有此函数;请查看您所使用的文档。例如,IBM 为AIX 5.3定义了一个compare_and_swap
函数。 但该函数不具有完整的内存屏障语义。文档注释如下:
如果将 compare_and_swap 用作锁定原语,请在任何关键部分的开头插入 isync。
从这个文档中我们可以猜测 IBM 的 compare_and_swap
具有释放语义:因为文档不要求在关键部分结束时使用屏障。获取处理器需要发出 isync 以确保其不会读取过期数据,但发布处理器则无需执行任何操作。
在指令级别上,一些处理器具有带有某些同步保证的比较和交换,而有些则没有。