我们知道当一个程序创建多线程运行时,多个线程之间会互相抢占。
所以即使此时运行最简单的a++;也可能会发生线程x的a++还没运行完,另一个线程y可能就抢占运行了,所以此时x线程a++就发生了错误。
下面就进行不同情况下的运行情况和时间消耗对比。
一,不加限制运行
代码:
#include<iostream>
#include<thread>
using namespace std;
const int tcount = 4;
int sum = 0;
void mythread()
{
for (int i = 0; i < 400000; i++)
{
sum++;
}
}
int main()
{
thread t[tcount];
for (int i = 0; i < tcount; i++)
{
t[i] = thread(mythread);
}
for (int i = 0; i < tcount; i++)
{
t[i].join();
}
cout<<"sum=" << sum << endl;
cout << "Hello,main thread" << endl;
system("pause");
return 0;
}
程序运行截图:
因为开了四个线程,每个线程都加了400000次,正常运行结果应该为1600000。可见这个结果是错误的,所以这种方法直接不能用。
二,将自加的过程上锁运行:mutex
不需要加太多代码:只需要加上头文件#include<mutex>
以及自加前后加锁解锁
m.lock(); sum++; m.unlock();
运行结果:
可见这个结果是正确的,但是试想一些加上锁的运行过程,进行了1600000次的加锁解锁的过程。对于资源的消耗很大,而且也浪费时间,所以此时就有了atomic。
三,使用原子性操作:atomic
atomic就是原子性操作,不用再加锁解锁,减少资源消耗。
修改部分:需要加上头文件<atomic>
然后把变量定义为原子的即可,下面直接自加就行;
atomic<int> sum_atomic = 0;
sum_atomic++;
运行结果:
可见这个也能运算成功,结果也是1600000。
使用时间对比两者的速率
代码:
#include<iostream>
#include<thread>
#include<mutex>
#include<chrono>
#include<atomic>
using namespace std;
using namespace std::chrono;
atomic<int> sum_atomic = 0;
mutex m;
const int tcount = 4;
int sum = 0;
void mythread()
{
for (int i = 0; i < 400000; i++)
{
//m.lock();
//sum++;
//m.unlock();
sum_atomic++;
}
}
int main()
{
thread t[tcount];
for (int i = 0; i < tcount; i++)
{
t[i] = thread(mythread);
}
time_point<high_resolution_clock> _begin=high_resolution_clock::now();;
for (int i = 0; i < tcount; i++)
{
t[i].join();
}
double now = ((long long)duration_cast<microseconds>(high_resolution_clock::now() - _begin).count())*0.001;
cout << "花费时间:" << now;
cout<<"sum_atomic=" << sum_atomic << endl;
//cout<< "sum=" << sum << endl;
cout << "Hello,main thread" << endl;
//631.275
//55.85
//9.973
system("pause");
return 0;
}
两种运行截图对比:
可见使用原子性操作的时间消耗相比于加锁解锁时间减少了500多毫秒。
因此使用原子性操作是最好的方法。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_46423166/article/details/111246391