首先看一下没有原子操作,多个线程对同一个整形++
这里使用的是互斥量进行加锁,加了两千万此,花了大约4.5秒
void threadEntryFunc()
{
//大约4.5秒
for (int i = 1; i <= 10000000; i++)
{
myMutex.lock();
myNum++;
myMutex.unlock();
}
}
int main()
{
std::thread myThread1(threadEntryFunc);
std::thread myThread2(threadEntryFunc);
myThread1.join();
myThread2.join();
std::cout << "the final result is " << myNum2 << std::endl;
}
原子操作改进
什么是原子操作?和互斥量有什么不同?
原子操作和互斥量不同的是 互斥量指的是进行加锁和释放锁,之间的代码段以同步的方式进行 而原子操作指的是对某个变量进行操作,对这个变量进行的操作都是不可分割的, ++就必须加上1,整个汇编中间的操作都被视为一整个操作,不能分割,这就造成了原子性 并且原子操作在效率上要远远高于互斥量的加锁解锁
//原子操作的变量声明,至于这个变量的用法,没有什么太大变化
std::atomic<int> myNum2= 0;
void threadEntryFunc()
{
//大约1.7秒左右,可以知道,效率大大提升
for (int i = 0; i < 10000000; i++)
{
myNum2++;
}
}
int main()
{
std::thread myThread1(threadEntryFunc);
std::thread myThread2(threadEntryFunc);
myThread1.join();
myThread2.join();
std::cout << "the final result is " << myNum2 << std::endl;
}
原子操作时间,主线程中关闭子线程
//原子变量声明
std::atomic<bool> isRunning = true;
//线程入口函数
void threadEntryFunc2()
{
//循环判断是否主线程中关闭了
while (isRunning)
{
std::cout << "线程 " << std::this_thread::get_id() << "运行中" << std::endl;
//线程休眠1秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "线程 " << std::this_thread::get_id() << "执行结束"<< std::endl;
}
int main()
{
std::thread myThread1(threadEntryFunc2);
std::thread myThread2(threadEntryFunc2);
std::thread myThread3(threadEntryFunc2);
//主线程等待10秒看运行结果
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
isRunning = false;
myThread1.join();
myThread2.join();
myThread3.join();
std::cout << "the final result is " << myNum2 << std::endl;
}
运行结果如下,可以分析出,主线程只要把握住原子操作的bool值,即可决定子线程的运行状态
atomic注意点
虽然是原子操作,但是使用的操作方法是有要求的,如下:
想一想,从汇编的角度,++,--都是某个变量本身的操作,而x = x+1 这就需要使用寄存器,把x先存到一个寄存器中,寄存器中值+1,在给x的地址赋上新的值, 这种操作本身就不是原子操作所指的某个变量本身进行的操作
#include <atomic>
std::atomic<int> myNum = 0;
void method1()
{
for(int i = 0 ; i < 10000000 ; i++)
{
//这种写法肯定是不行的,支持的写法有
//++
//--
//+=
//-=
//!=
//是这种结构的
myNum = myNum+1;
}
}
int main()
{
std::thread myThread1(method1);
std::thread myThread2(method1);
myThread1.join();
myThread2.join();
std::cout<<"the answer is "<<myNum<<std::endl;
}