C++中atomic 資料型別操作
所謂的原子操作,取的就是“原子是最小的、不可分割的最小個體”的意義,它表示在多個執行緒訪問同一個全域性資源的時候,能夠確保所有其他的執行緒都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的執行緒對這個資源進行訪問。這有點類似互斥物件對共享資源的訪問的保護,但是原子操作更加接近底層,因而效率更高。
在以往的C++標準中並沒有對原子操作進行規定,我們往往是使用匯編語言,或者是藉助第三方的執行緒庫,例如intel的pthread來實現。在新標準C++11,引入了原子操作的概念,並通過這個新的標頭檔案提供了多種原子操作資料型別,例如,atomic_bool,atomic_int等等,如果我們在多個執行緒中對這些型別的共享資源進行操作,編譯器將保證這些操作都是原子性的,也就是說,確保任意時刻只有一個執行緒對這個資源進行訪問,編譯器將保證,多個執行緒訪問這個共享資源的正確性。從而避免了鎖的使用,提高了效率。
我們還是來看一個實際的例子。假若我們要設計一個廣告點選統計程式,在伺服器程式中,使用多個執行緒模擬多個使用者對廣告的點選:
#include <boost/thread/thread.hpp>
#include <atomic>
#include <iostream>
#include <time.h>
using namespace std;
// 全域性的結果資料
long total = 0;
// 點選函式
void click()
{
for(int i=0; i<1000000;++i)
{
// 對全域性資料進行無鎖訪問
total += 1;
}
}
int main(int argc, char* argv[])
{
// 計時開始
clock_t start = clock();
// 建立100個執行緒模擬點選統計
boost::thread_group threads;
for(int i=0; i<100;++i)
{
threads.create_thread(click);
}
threads.join_all();
// 計時結束
clock_t finish = clock();
// 輸出結果
cout<<"result:"<<total<<endl;
cout<<"duration:"<<finish -start<<"ms"<<endl;
return 0;
}
從執行的結果來看,這樣的方法雖然非常快,但是結果不正確
E:\SourceCode\MinGW>thread.exe
result:87228026
duration:528ms
很自然地,我們會想到使用互斥物件來對全域性共享資源的訪問進行保護,於是有了下面的實現:
long total = 0;
// 對共享資源進行保護的互斥物件
mutex m;
void click()
{
for(int i=0; i<1000000;++i)
{
// 訪問之前,鎖定互斥物件
m.lock();
total += 1;
// 訪問完成後,釋放互斥物件
m.unlock();
}
}
互斥物件的使用,保證了同一時刻只有唯一的一個執行緒對這個共享進行訪問,從執行的結果來看,互斥物件保證了結果的正確性,但是也有非常大的效能損失,從剛才的528ms變成了現在的8431,用了原來時間的10多倍的時間。這個損失夠大。
E:\SourceCode\MinGW>thread.exe
result:100000000
duration:8431ms
如果是在C++11之前,我們的解決方案也就到此為止了,但是,C++對效能的追求是永無止境的,他總是想盡一切辦法榨乾CPU的效能。在C++11中,實現了原子操作的資料型別(atomic_bool,atomic_int,atomic_long等等),對於這些原子資料型別的共享資源的訪問,無需藉助mutex等鎖機制,也能夠實現對共享資源的正確訪問。
// 引入原子資料型別的標頭檔案
#include <atomic>
// 用原子資料型別作為共享資源的資料型別
atomic_long total(0);
//long total = 0;
void click()
{
for(int i=0; i<1000000;++i)
{
// 僅僅是資料型別的不同而以,對其的訪問形式與普通資料型別的資源並無區別
total += 1;
}
}
我們來看看使用原子資料型別之後的效果如何:
E:\SourceCode\MinGW>thread.exe
result:100000000
duration:2105ms
結果正確!耗時只是使用mutex互斥物件的四分之一!也僅僅是不採用任何保護機制的時間的4倍。可以說這是一個非常不錯的成績了。
原子操作的實現跟普通資料型別類似,但是它能夠在保證結果正確的前提下,提供比mutex等鎖機制更好的效能,如果我們要訪問的共享資源可以用原子資料型別表示,那麼在多執行緒程式中使用這種新的等價資料型別,是一個不錯的選擇。
相關推薦
C++中atomic 資料型別操作
所謂的原子操作,取的就是“原子是最小的、不可分割的最小個體”的意義,它表示在多個執行緒訪問同一個全域性資源的時候,能夠確保所有其他的執行緒都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的執行緒對這個資源進行訪問。這有點類似互斥物件對共享資源的訪
Object-C 中各資料型別轉換 NSData轉NSString,Byte,UIImage
1,NSData 與 NSString NSData --> NSString NSString *aString = [[NSString alloc] initWithData:adata encoding:NSUTF8StringEncoding]; NSStri
C/C++中各種 資料型別、結構體、類 佔用位元組數分析與總結
一、基本資料型別在不同編譯器下佔用位元組數比較與總結,測試過程不詳述了,直接看下錶結論! 下表中右側總結部分是依據佔用位元組數進行著色,同一種顏色型別的資料成員佔用位元組數要麼一致,要麼具有同樣的性質,這樣比較容易理解的記憶。 佔用位元組數
C++中輸入資料型別判斷,輸入型別錯誤後,提示使用者重新輸入直至其輸入正確
要求輸入number,但是使用者鍵入了字母A,仍然有結果,但是不正確,同時後面的程式碼自行運行了,沒有辦法去輸入string了。所以要改進,可以判斷輸入的是否為正確的資料型別 利用cin.good()和cin.fail()判斷: cin.good()為true時,輸入的資料型別與定
C++中基本資料型別位元組數及取值範圍【轉】
【轉自】:http://blog.csdn.net/a775992553/article/details/8790241 機器字長:是指計算機進行一次整數運算所能處理的二進位制資料的位數(整數運算即定點整數運算)。機器字長也就是運算器進行定點數運算的字長,通常也是CPU內部資料通路的寬度。現在一
詳解C++中基本資料型別位元組數
C標準中並沒有具體規定哪個基本型別應該是多少位元組數,但有幾條鐵定的原則(ANSI/ISO制訂的): sizeof(short int)<=sizeof(int) sizeof(int)<=sizeof(long int) short
Object-c 中的資料型別
導航: 基本型別 ID 物件型別常見的有 物件型別 -NSLog -NSNumber -NSString和NSMutableString -NSArray和NSMutableArray -NSSet和NSMutableSet -NSDictionar
學習筆記(C++中基礎資料型別在記憶體的表現形式)
一、整數型別 C++提供的整數型別有三種:int long short ,在Microsoft Visual C++ 6.0中,int型別與long型別在記憶體中都佔4個位元組,short型別佔兩個位元組。 在C++中整數型別又可以分為有符號與無符號型別兩種。 無符號整
C/C++中基本資料型別在不同系統中所佔空間大小
關於這個基本的問題,很早以前就很清楚了,C標準中並沒有具體給出規定那個基本型別應該是多少位元組數,而且這個也與機器、OS、編譯器有關,比如同樣是在32bits的作業系統系,VC++的編譯器下int型別
C++中的資料型別轉換方法總結
int到char*,或者反過來從char*到int,在C/C++中到底有多少種轉換方法呢?符合標準的大概有四種。即C資料轉換函式族、sprintf/snprintf/sscanf函式族、字串流std::stringstream、std::strsteam。不符合標準卻又廣為使用的包括CString和boost
C++中的資料型別轉換方法
摘要:本文總結了C/C++中的多種資料型別轉換方法,並比較了各自的優劣。給出了推薦的使用建議。 從int到char*,或者反過來從char*到int,在C/C++中到底有多少種轉換方法呢?符合標準的大概有四種。即C資料轉換函式族、sprintf/snprintf/sscanf函式族、字串流std::stri
C#實體類中在資料型別後面新增問號是什麼意思
C#實體類中在資料型別後面新增問號是什麼意思 public static DateTime? GetTimeStartByType(DataTimeType type, DateTime time) C#語法中一個個問號(?)的運算子是指:可以為 null
redis常見資料型別操作命令,Java中使用Jedis操作Redis
redis常見資料型別操作命令 可參考地址:Http://redisdoc.com/ Java中使用Jedis操作Redis: https://www.cnblogs.com/liuling/p/2014-4-19-04.html redis鍵(key)
redis中各種資料型別對應的jedis操作命令
一、常用資料型別簡介: redis常用五種資料型別:string,hash,list,set,zset(sorted set). 1.String型別 String是最簡單的型別,一個key對應一個value String型別的資料最大1G。 String
c語言中的資料型別
c語言中的資料型別 "資料型別": { "基本資料型別":{ //%d 以整數型輸出 "整型":{ //int 4位元組 -
小白眼中的Python3.0中對資料型別List的相關操作
PS:本人小白,剛開始自學,先重在使用,再由淺入深,其中有現階段未領悟到的和筆誤,望前輩指出修正 :) 轉載也請註明出處哦~ 因為學完了Python中資料型別List的章節,所以對個別常用相關操作做個彙總,日後再慢慢增加,做個備忘 1. 建立List資料
C++11 —— 獲取 tuple 引數列表中指定資料型別的索引位置
1. 問題背景 在 C++11 的標準中,我們可以通過 std::get< Index >(tuple) (以常量整數值為索引號)操作 tuple 中的引數,而到了 C++14 之後的標準,新增了 std::get< Type >(tuple) (以資料型別為索引)的方式操作 t
C# 中Bitmap和Halcon中HObject資料型別的相互轉換
C# 中Bitmap和Halcon中HObject資料型別的相互轉換 public void Bitmap2HObjectBpp24(Bitm
C#讀取SharePoint的List中的資料及操作SharePoint
一般SharePoint都有提供一個webservice來訪問、操作SharePoint的各項資料。 地址一般為http://server/_vti_bin/Lists.asmx 下面是一個簡單的讀取SharePoint List資料的例子: &
檔案是資料(位元組)流的抽象-為什麼C++中會把檔案操作抽象為fstream?
這不過是返祖罷了。正確的問題是為什麼會把資料流抽象成檔案。 裝置-位元組流-檔案。 一切皆為檔案,所有不同種類的型別都被抽象成檔案(比如:塊裝置,socket套接字,pipe佇列)。 檔案抽象為資料流一定程度上是 Unix 造成的。 傳統上,計算機上用