多线程的数据访问一直很让程序员们头大,有什么简便方法来实现多线程间的通呢?试试C++11封装的原子数据类型(std::atomic)吧。
1什么是原子数据类型
简单地说,原子数据类型能保证线程之间不会发生数据竞争(data race),因此能保证线程安全(thread safe)。
对于我们用户来说,就不需要对需要多线程访问的数据添加互斥锁。从不同线程访问某个原子对象是良性(well-defined) 行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义(undefined) 行为发生。因此,从实现的原理上来,可以理解为原子类型在自己内部添加了互斥锁。
我们先创建一个CMake工程,并创建两个线程来操作同一个全局变量,然后来编译运行,查看它的结果。接下来,我们会针对这个结果进行改造,使之达到我们想要的“线程安全”的要求。2测试环境
系统:Ubuntu 16.04/18.04/20.04
编程语言:C++
测试代码:https://github.com/one-third-robot/article-003-atomic
工程1:不使用原子数据类型
第一个工程,演示的是如果不使用原子数据类型,程序会产生一定的错误。工程代码可在以上GitHub链接中找到,工程文件名为no-atomic.cpp
,内容如下:
#include
#include
#include
#include
#include
int data( 0 );
void threadFunc() {
for ( int i = 0; i < 2000; i++ ) {
usleep( 1 );
data++;
}
}
int main( int argc, char* argv[] ) {
std::thread th1( threadFunc );
std::thread th2( threadFunc );
th1.join();
th2.join();
usleep( 20000 );
std::cout << "data = " << data << std::endl;
return 0;
}
这里的
data
是一个全局变量(当然实际工程当中使用全局变量不是一个好的习惯,我们这里只是演示),初始值为0。在