一:概述
项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式。
为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一个线程执行过程中可能被内核临时挂起,这就是线程切换,当内核再次切换到该线程时,之前的数据可能已被修改,不能保证原子操作。
C++11提供了个原子的类和方法atomic,保证了多线程对变量原子性操作,相比加锁机制mutex.locak(),mutex.unlocak(),性能有几倍的提升。
所需头文件
二:错误代码
1 //全局变量
2 int g_num = 0;
3
4 void fun()
5 {
6 for (int i = 0; i < 10000000; i++)
7 {
8 g_num++;
9 }
10 return ;
11 }
12
13 int main()
14 {
15 //创建线程1
16 thread t1(fun);
17 //创建线程2
18 thread t2(fun);
19 t1.join();
20 t2.join();
21
22 cout << g_num << endl;
23 getchar();
24 return 1;
25 }
应该输出结果20000000,实际每次结果都不一样,总是小于该值,正是由于多线程操作同一变量而没有保证原子性导致的。
三:加锁代码
1 //全局变量
2 int g_num = 0;
3 mutex m_mutex;
4
5 void fun()
6 {
7 for (int i = 0; i < 10000000; i++)
8 {
9 m_mutex.lock();
10 g_num++;
11 m_mutex.unlock();
12 }
13 return ;
14 }
15
16 int main()
17 {
18 //获取当前毫秒时间戳
19 typedef chrono::time_point<:system_clock chrono::milliseconds> microClock_type;
20 microClock_type tp1 = chrono::time_point_cast<:milliseconds>(chrono::system_clock::now());
21 long long time1 = tp1.time_since_epoch().count();
22
23 //创建线程
24 thread t1(fun);
25 thread t2(fun);
26 t1.join();
27 t2.join();
28
29 cout << "总数:" << g_num << endl;
30
31 //获取当前毫秒时间戳
32 microClock_type tp2 = chrono::time_point_cast<:milliseconds>(chrono::system_clock::now());
33 long long time2 = tp2.time_since_epoch().count();
34 cout << "耗时:" << time2 - time1 << "ms" << endl;
35
36 getchar();
37 return 1;
38 }
执行结果:多次测试输出均为20000000,耗时在3.8s左右
四:atomic原子操作代码
1 //全局变量
2 atomic g_num = 0;
3
4 void fun()
5 {
6 for (int i = 0; i < 10000000; i++)
7 {
8 g_num++;
9 }
10 return ;
11 }
12
13 int main()
14 {
15 //获取当前毫秒时间戳
16 typedef chrono::time_point<:system_clock chrono::milliseconds> microClock_type;
17 microClock_type tp1 = chrono::time_point_cast<:milliseconds>(chrono::system_clock::now());
18 long long time1 = tp1.time_since_epoch().count();
19
20 //创建线程
21 thread t1(fun);
22 thread t2(fun);
23 t1.join();
24 t2.join();
25
26 cout << "总数:" << g_num << endl;
27
28 //获取当前毫秒时间戳
29 microClock_type tp2 = chrono::time_point_cast<:milliseconds>(chrono::system_clock::now());
30 long long time2 = tp2.time_since_epoch().count();
31 cout << "耗时:" << time2 - time1 << "ms" << endl;
32
33 getchar();
34 return 1;
35 }
执行结果:多次测试输出均为20000000,耗时在1.3s左右
五:总结
c++11的原子类atomic相比使用加锁机制性能有2~3倍提升,对于共享变量能用原子类型的就不要再用加锁机制了。