1. 程式人生 > >C++ 多執行緒 atomic

C++ 多執行緒 atomic

atomic 先上翻譯。

aotomic原子的 即不能分割的,最小單位。

舉個例子,int num;

num = num +1;

我們都知道對於num=num+1這條程式語句需要分解為三步,

1、把變數num讀取到某一個暫存器R儲存,

2、CPU對暫存器R的值進行計算,

3、計算完成後將值存回記憶體

在多執行緒執行num++的時候 當前num為1 執行緒A執行完第二步 此時num為2但是還沒有存入記憶體,然後執行緒B開始執行第一步,從記憶體中取出num,num依舊是1,這樣就出現問題了,相當於A執行緒和B執行緒一共執行了連詞num=num+1,但是num卻只增加了1,。

我們測試一下:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<thread>
#include<map>
#include<stack>
#include<vector>
#include<atomic>
#include<Windows.h>
#include<algorithm>
using namespace std;
class Unit
{
public :
	Unit() { this->num = 0; this->step = 0; this->numnum = 0; this->stepnum = 0; };
	void ChangeStepNum()
	{
		step = step + 1;
		num = num + 1;
		//++step;
		//++num;
	}
	void ChangeStep()
	{
		step++;
	}
	void ChangeNum()
	{
		num++;
	}
	void GetAve()
	{
		if (this->num == this->step)
			cout << "Good" << endl;
		else
			cout << "Bad" << endl;
	}
	void PrintStepNum()
	{
		cout << "num" << this->num << endl;
		cout <<"step" << this->step << endl;
	}
	void equal()
	{
		if (this->num != this->step)
			cout << "???" << endl;
	}
private :
	//atomic <int> step;
	//atomic <int> num;
	int step;//定義變數
	int num;//讓這兩個變數同時改變
	int stepnum;
	int numnum;
};
void Change(Unit &unit)//同時改變兩個變數
{
	for (int i = 0; i < 10000; i++)
	{
		//unit.equal();
		unit.ChangeNum();
		unit.ChangeStep();
	}
	unit.GetAve();
}
int main()
{
	Unit unit;

	thread t1(Change, ref(unit));//執行緒1
	thread t2(Change, ref(unit));//執行緒2
	t1.join();
	t2.join();
	unit.PrintStepNum();
	Sleep(1000);
	for (int i = 0; i < 10000; i++)
	{
		unit.ChangeNum();
		unit.ChangeStep();
	}
	unit.PrintStepNum();
}

測試結果

我們可以看到,由於上邊闡述的原因 ,導致num和step一共改變了20000次但是最後結果卻不是20000,而且num!=step.

如果我們改成原子操作atomic,即atomic修飾的操作不可分割,未 修飾是num=num+1執行了三步:修飾之後變成了一步,變成了一個原子,不可分割。

	atomic <int> step;
	atomic <int> num;
	//int step;//定義變數
	//int num;//讓這兩個變數同時改變

測試結果

如果num== step就輸出good 否則輸出bad。

我們可以看到num是== step 的 而且 經過20000次++之後  ,確實加到了20000。

不過 還有一個問題,就是num和step是一起操作的,但是num和step一直都相等嗎。

應該不是的,對於AB兩個執行緒

void Change(Unit &unit)//同時改變兩個變數
{
	for (int i = 0; i < 10000; i++)
	{
		//unit.equal();
		unit.ChangeNum();
		unit.ChangeStep();
	}
	unit.GetAve();
}

可能A執行緒剛執行到changenum時,B執行緒已經執行到changestep了,雖然我們給這兩個變數加了atomic。

此時我們在change之前加一個判斷函式,如果num!=step則問號警告。

測試一下:

可以得出,雖然最後num是==step的,但是在中間執行過程中並不是一直相等的。