线程是一个相当复杂的低级功能。从历史上看,没有标准的 C 线程功能,而是在不同的操作系统上以不同的方式完成。今天主要是 POSIX 线程标准,它已经在 Linux 和 BSD 中实现,现在通过扩展 OS X,还有 Windows 线程,从 Win32 及更高版本开始。除了这些之外,可能还有其他系统。
GCC 不直接包含 POSIX 线程实现,相反它可能是 linux 系统上libpthread 的客户端。当您从源代码构建 GCC 时,您必须单独配置和构建许多辅助库,以支持诸如大数字和线程之类的东西。这就是您选择如何进行线程化的点。如果您在 linux 上以标准方式执行此操作,您将在 pthreads 方面实现 std::thread。
在 Windows 上,从符合 MSVC C++11 开始,MSVC 开发人员在本机 Windows 线程接口方面实现了 std::thread。
操作系统的工作是确保其 API 提供的并发锁确实有效——std::thread 旨在成为此类原语的跨平台接口。
对于更奇特的平台/交叉编译等,情况可能会更复杂。例如,在 MinGW 项目(Windows 的 gcc)中——从历史上看,您可以选择使用 pthread 端口构建 MinGW gcc 到 Windows ,或使用基于原生 win32 的线程模型。如果您在构建时没有配置它,您最终可能会得到一个不支持 std::thread 或 std::mutex 的 C++11 编译器。有关更多详细信息,请参阅此问题。 MinGW error: ‘thread’ is not a member of ‘std’
现在,更直接地回答您的问题。当使用互斥体时,在最低级别,这涉及到一些对 libpthreads 或一些 win32 API 的调用。
pthread_lock_mutex();
do_some_stuff();
pthread_unlock_mutex();
(pthread_lock_mutex 和 pthread_unlock_mutex 对应于您的平台上 std::mutex 的 lock 和 unlock 的实现,并且在惯用的 C++11 代码中,这些又在 @987654336 中调用@ 和 dtor 的 std::unique_lock,例如,如果您正在使用它。)
通常,优化器无法重新排序这些,除非确定 pthread_lock_mutex() 没有可以改变 do_some_stuff() 的可观察行为的副作用。
据我所知,编译器执行此操作的机制最终与它用于估计调用任何其他外部库的潜在副作用的机制相同。
如果有资源
int resource;
各个线程争用,表示有函数体
void compete_for_resource();
并且指向 this 的函数指针在较早的某个时间点传递给程序中的pthread_create... 以启动另一个线程。 (这可能是在std::thread 的ctor 的实现中。)此时,编译器可以看到对libpthread 的任何调用都可能调用compete_for_resource 并触及该函数触及的任何内存。 (从编译器的角度来看,libpthread 是一个黑匣子——它是一些 .dll / .so,它无法假设它究竟做了什么。)
特别是,调用pthread_lock_mutex(); 可能对resource 有副作用,因此不能针对do_some_stuff() 重新排序。
如果您实际上从未产生任何其他线程,那么据我所知,do_some_stuff(); 可以在互斥锁之外重新排序。既然,那么libpthread 对resource 没有任何访问权限,它只是您源代码中的一个私有变量,甚至不会间接与外部库共享,编译器可以看到这一点。