一:概述
项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式。
为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一个线程执行过程中可能被内核临时挂起,这就是线程切换,当内核再次切换到该线程时,之前的数据可能已被修改,不能保证原子操作。
C++11提供了个原子的类和方法atomic,保证了多线程对变量原子性操作,相比加锁机制mutex.lock(),mutex.unlock(),性能有几倍的提升。
所需头文件<atomic>
二:错误代码
-
//全局变量
-
int g_num =
0;
-
-
void fun()
-
{
-
for (
int i =
0; i <
10000000; i++)
-
{
-
g_num++;
-
}
-
return ;
-
}
-
-
int main()
-
{
-
//创建线程1
-
thread t1(fun);
-
//创建线程2
-
thread t2(fun);
-
t1.join();
-
t2.join();
-
-
cout << g_num <<
endl;
-
getchar();
-
return
1;
-
}
应该输出结果20000000,实际每次结果都不一样,总是小于该值,正是由于多线程操作同一变量而没有保证原子性导致的。
三:加锁代码
-
//全局变量
-
int g_num =
0;
-
mutex m_mutex;
-
-
void fun()
-
{
-
for (
int i =
0; i <
10000000; i++)
-
{
-
m_mutex.lock();
-
g_num++;
-
m_mutex.unlock();
-
}
-
return ;
-
}
-
-
int main()
-
{
-
//获取当前毫秒时间戳
-
typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
-
microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
-
long
long time1 = tp1.time_since_epoch().count();
-
-
//创建线程
-
thread t1(fun);
-
thread t2(fun);
-
t1.join();
-
t2.join();
-
-
cout <<
"总数:" << g_num <<
endl;
-
-
//获取当前毫秒时间戳
-
microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
-
long
long time2 = tp2.time_since_epoch().count();
-
cout <<
"耗时:" << time2 - time1 <<
"ms" <<
endl;
-
-
getchar();
-
return
1;
-
}
执行结果:多次测试输出均为20000000,耗时在3.8s左右
四:atomic原子操作代码
-
//全局变量
-
atomic<
int> g_num =
0;
-
-
void fun()
-
{
-
for (
int i =
0; i <
10000000; i++)
-
{
-
g_num++;
-
}
-
return ;
-
}
-
-
int main()
-
{
-
//获取当前毫秒时间戳
-
typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
-
microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
-
long
long time1 = tp1.time_since_epoch().count();
-
-
//创建线程
-
thread t1(fun);
-
thread t2(fun);
-
t1.join();
-
t2.join();
-
-
cout <<
"总数:" << g_num <<
endl;
-
-
//获取当前毫秒时间戳
-
microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
-
long
long time2 = tp2.time_since_epoch().count();
-
cout <<
"耗时:" << time2 - time1 <<
"ms" <<
endl;
-
-
getchar();
-
return
1;
-
}
执行结果:多次测试输出均为20000000,耗时在1.3s左右
五:总结
c++11的原子类atomic相比使用加锁机制性能有2~3倍提升,对于共享变量能用原子类型的就不要再用加锁机制了。
<li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-thumbsup"></use> </svg><span class="name">点赞</span> <span class="count">3</span> </a></li> <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-Collection-G"></use> </svg><span class="name">收藏</span></a></li> <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-fenxiang"></use> </svg>分享</a></li> <!--打赏开始--> <!--打赏结束--> <li class="tool-item tool-more"> <a> <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg> </a> <ul class="more-box"> <li class="item"><a class="article-report">文章举报</a></li> </ul> </li> </ul> </div> </div> <div class="person-messagebox"> <div class="left-message"><a href="https://blog.youkuaiyun.com/woniu211111"> <img src="https://profile.csdnimg.cn/D/6/9/3_woniu211111" class="avatar_pic" username="woniu211111"> <img src="https://g.csdnimg.cn/static/user-reg-year/2x/10.png" class="user-years"> </a></div> <div class="middle-message"> <div class="title"><span class="tit"><a href="https://blog.youkuaiyun.com/woniu211111" data-report-click="{"mod":"popu_379"}" target="_blank">码农code之路</a></span> <span class="flag expert"> <a href="https://blog.youkuaiyun.com/home/help.html#classicfication" target="_blank"> <svg class="icon" aria-hidden="true"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-blogexpert"></use> </svg> 博客专家 </a> </span> </div> <div class="text"><span>发布了134 篇原创文章</span> · <span>获赞 255</span> · <span>访问量 69万+</span></div> </div> <div class="right-message"> <a href="https://bbs.youkuaiyun.com/topics/395527914" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板 </a> <a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a> </div> </div> </div>