使用pthread互斥锁保护变量是否保证它也不会被缓存?

Ano*_*nym 33 c pthreads

考虑一个简单的(在我的情况下是全局)变量:

int i;
Run Code Online (Sandbox Code Playgroud)

在某处访问此变量

pthread_mutex_lock(i_mutex);
if(i == other value) {
  do_something();
}
pthread_mutex_unlock(i_mutex);
Run Code Online (Sandbox Code Playgroud)

另一个线程i 在保持时更新i_mutex.编译器可以缓存值,i所以我没有得到最近的值?一定i是不稳定的?

Mic*_*urr 36

pthread锁实现内存屏障,以确保缓存效果对其他线程可见.如果对共享变量i的访问受pthread互斥锁保护,则不需要volatile来正确处理共享变量.

来自http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11:

以下函数使内存与其他线程同步:

fork()
pthread_barrier_wait()
pthread_cond_broadcast()
pthread_cond_signal()
pthread_cond_timedwait()
pthread_cond_wait()
pthread_create()
pthread_join()
pthread_mutex_lock()       // <====
pthread_mutex_timedlock()
pthread_mutex_trylock()
pthread_mutex_unlock()     // <====
pthread_spin_lock()
pthread_spin_trylock()
pthread_spin_unlock()
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()
sem_post()
sem_timedwait()
sem_trywait()
sem_wait()
semctl()
semop()
wait()
waitpid()
Run Code Online (Sandbox Code Playgroud)

  • @Anonym:不,这不是因为pthread_mutex_XX,而是因为函数调用(C中的一个序列点).见Jens Gustedt的回答.内存屏障不能防止缓存,它可以防止重新排序(它不会让访问跨越屏障). (6认同)
  • @ninjalj:函数调用序列点*组合*与pthreads函数提供的内存屏障确保将使用一致的`i`值.单独的序列点是不够的,因为没有内存屏障缓存效果可能会读取过时的值`i`,即使编译器在函数调用后插入一个内存读取(例如,如果调用了一些非pthread函数). (6认同)
  • @Anonym:差不多了。该函数调用避免了缓存,并充当了编译器屏障(防止了编译器对访问屏障进行重新排序,从而避免了编译器屏障的出现)。CPU屏障可能会阻止CPU重新排序跨CPU屏障的访问。互斥锁可防止同时访问受保护的数据。我的理解也是如此。对于精美的细节,您肯定需要一个向导,一个简单的大师​​将无法完成; P (2认同)

Jen*_*edt 5

编译器不应在函数调用中缓存此类全局值.

但我认为你的问题不合适.首先,POSIX互斥锁仅在您坚持其语义时才起作用.因此,您必须在代码中应用一些规则,以便只访问i您的互斥锁保持的全局变量(在这种情况下).

其次,请不要认为volatile声明会阻止您对这种不遵守访问规则会造成的任何损害.并发读写内存是一个微妙的主题.