Win32 / pthreads线程函数的volatile-Correctness

时间:2014-09-20 01:21:31

标签: c++ multithreading winapi pthreads mutex

在阅读this wonderful article之后,我开始深入研究一些代码。挥发性正确性的一个结果(据我所知)是从不同线程访问的方法应该是volatile限定的。

一个简单的例子可能是使用Win32或pthreads的互斥锁。我们可以创建一个类Mutex并给它一个字段:

#if   defined BACKEND_WIN32
    CRITICAL_SECTION _lock;
#elif defined BACKEND_POSIX
    pthread_mutex_t _lock;
#endif

" .acquire()"方法可能如下所示:

void Mutex::acquire(void) volatile {
    #if   defined BACKEND_WIN32
        EnterCriticalSection(&_lock);
    #elif defined BACKEND_POSIX
        pthread_mutex_lock(&_lock);
    #endif
}

尝试这个并不奏效。来自MSVC:

  

错误C2664:' void EnterCriticalSection(LPCRITICAL_SECTION)' :无法从< volatile CRITICAL_SECTION *'转换参数1到' LPCRITICAL_SECTION'

来自g ++:

  

错误:从'volatile pthread_mutex_t *'无效转换为'pthread_mutex_t *'[-fpermissive]

您尝试解锁_lock时会遇到类似问题。两个问题:

  • 我的印象是,这些只是过时的API的工件。事实上是这样的吗?我误解了什么吗?
  • 锁定或解锁API函数的整个目的是在关键部分之间切换,因此,我应该使用名称不足const_cast的情况在传递给这些函数之前抛弃了volatile的{​​{1}} - _lock,没有任何不良影响?

1 个答案:

答案 0 :(得分:1)

我认为volatile标准(现在)的最佳总结可以在n3797 S7.1.6.1 / 6/7中找到

  

对具有volatile限定类型的对象的访问构成是实现定义的。如果尝试通过使用具有非volatile限定类型的glvalue来引用使用volatile限定类型定义的对象,则程序行为是未定义的。

     

[注意:volatile是对实现的暗示,以避免涉及对象的激进优化,因为对象的值可能会被实现无法检测到的更改。此外,对于某些实现,volatile可能指示访问对象需要特殊的硬件指令。有关详细语义,请参见1.9。一般来说,volatile的语义在C ++中与在C语言中的含义相同。-end note]

可悲的是,这意味着符合标准的实施不需要像该文章所暗示的那样做。没有义务及时存储值,并且有义务重新加载可能已更改的值。编译器不能自由地加载加载它尚未存储的值的代码,但可以自由地删除存储它从未使用过的值的代码。

如评论中所述,最好使用实现定义的API或atomicmutex。挥发会让你失望。 Stroustrup在链接的question中说了很多。