這篇文章主要介紹“怎么實現(xiàn)C++寫時拷貝”,在日常操作中,相信很多人在怎么實現(xiàn)C++寫時拷貝問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么實現(xiàn)C++寫時拷貝”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)專注于涿州企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),電子商務(wù)商城網(wǎng)站建設(shè)。涿州網(wǎng)站建設(shè)公司,為涿州等地區(qū)提供建站服務(wù)。全流程按需策劃,專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
一、什么是寫時拷貝
寫入時復(fù)制是一種計算機程序設(shè)計領(lǐng)域的優(yōu)化策略。其核心思想是,如果有多個調(diào)用者同時請求相同資源(如內(nèi)存或磁盤上的數(shù)據(jù)存儲),他們會共同獲取相同的指針指向相同的資源,直到某個調(diào)用者試圖修改資源的內(nèi)容時,系統(tǒng)才會真正復(fù)制一份專用副本(private copy)給該調(diào)用者,而其他調(diào)用者所見到的最初的資源仍然保持不變。
這個過程對其他的調(diào)用者是透明的(transparently)。
此作法的主要優(yōu)點是如果調(diào)用者沒有修改該資源,就不會有副本被建立,因此多個調(diào)用者只是讀取操作是可以共享同一份資源。
寫時拷貝技術(shù)是一種很重要的優(yōu)化手段,核心是懶惰處理實體資源請求,在多個實體資源之間只是共享資源,起初是并不真正實現(xiàn)資源拷貝,只有當(dāng)實體有需要對資源進行修改時才真正為實體分配私有資源。但寫時拷貝技術(shù)技術(shù)也有它的優(yōu)點和缺點:
1、寫時拷貝技術(shù)可以減少分配和復(fù)制大量資源時帶來的瞬間延時,但實際上是將這種延時附加到了后續(xù)的操作之中。
2、寫時拷貝技術(shù)可以減少不必要的資源分配。比如fork進程時,并不是所有的頁面都需要復(fù)制,父進程的代碼段和只讀數(shù)據(jù)段都不被允許修改,所以無需復(fù)制。
二、寫時拷貝技術(shù)的應(yīng)用
1、虛擬內(nèi)存管理中的寫時復(fù)制
一般把這種被共享訪問的頁面標記為只讀。當(dāng)一個task試圖向內(nèi)存中寫入數(shù)據(jù)時,內(nèi)存管理單元(MMU)拋出一個異常,內(nèi)核處理該異常時為該task分配一份物理內(nèi)存并復(fù)制數(shù)據(jù)到此內(nèi)存,重新向MMU發(fā)出執(zhí)行該task的寫操作。
比如 Linux的fork()使用寫時拷貝頁來實現(xiàn)新進程的創(chuàng)建,它是一種可推遲甚至避免數(shù)據(jù)拷貝的技術(shù),開始時內(nèi)核并不會復(fù)制整個地址空間,而是讓父子進程共享地址空間,只有在寫時才復(fù)制地址空間,使得父子進程都擁有獨立的地址空間,即資源的復(fù)制是在只有需要寫入時才會發(fā)生。在此之前都是以讀的方式去和父進程共享資源,這樣,在頁根本不會被寫入的場景下,fork()立即執(zhí)行exec(),無需對地址空間進行復(fù)制,fork()的實際開銷就是復(fù)制父進程的一個頁表和為子進程創(chuàng)建一個進程描述符,也就是說只有當(dāng)進程空間中各段的內(nèi)存內(nèi)容發(fā)生變化時,父進程才將其內(nèi)容復(fù)制一份傳給子進程,大大提高了效率。
2、數(shù)據(jù)存儲中的寫時復(fù)制
Linux等的文件管理系統(tǒng)使用了寫時復(fù)制策略。
舉個例子,比如我們有個程序要寫文件,不斷地根據(jù)網(wǎng)絡(luò)傳來的數(shù)據(jù)寫,如果每一次fwrite或是fprintf都要進行一個磁盤的I/O操作的話,都簡直就是性能上巨大的損失,
因此通常的做法是,每次寫文件操作都寫在特定大小的一塊內(nèi)存中(磁盤緩存),只有當(dāng)我們關(guān)閉文件時,才寫到磁盤上(這就是為什么如果文件不關(guān)閉,所寫的東西會丟失的原因)
3、軟件應(yīng)用中的寫時復(fù)制
在我們經(jīng)常使用的STL標準模板庫中的string類,也是一個具有寫時才拷貝技術(shù)的類。為了提高性能,STL中的許多類都采用了寫時拷貝技術(shù)。但是在C++11標準中為了提高并行性取消了這一策略
class String { public: //構(gòu)造函數(shù)(分存內(nèi)存) String(char* tmp) { _Len = strlen(tmp); _Ptr = new char[_Len + 1 + 1]; strcpy(_Ptr, tmp); // 在數(shù)組尾部設(shè)置引用計數(shù) _Ptr[_Len + 1] = 0; } //析構(gòu)函數(shù) ~String() { //引用計數(shù)減一 _Ptr[_Len + 1]--; // 引用計數(shù)為0時,釋放內(nèi)存 if (_Ptr[_Len + 1] == 0) { delete[] _Ptr; } } //拷貝構(gòu)造(共享內(nèi)存) String(string& str) { if (this->_Ptr != str) { //共享內(nèi)存,.data()返回的是將string的類型轉(zhuǎn)換成char類型的指針 const char *p = str.c_str(); char* pp; strcmp(pp, p); this->_Ptr = pp; this->_Len = str.size(); this->_Ptr[_Len + 1] ++; //引用計數(shù)加一 } } //對[]符進行重載,對字符串進行操作的時候,開始寫時復(fù)制 char& operator[](unsigned int idx) { if (idx > _Len || _Ptr == 0) { static char nullchar = 0; return nullchar; } //引用計數(shù)減一 _Ptr[_Len + 1]--; char* tmp = new char[_Len + 1 + 1]; strncpy(tmp, _Ptr, _Len + 1); _Ptr = tmp; // 設(shè)置新的共享內(nèi)存的引用計數(shù) _Ptr[_Len + 1] = 0; return _Ptr[idx]; } private: int _Len; char* _Ptr; };
到此,關(guān)于“怎么實現(xiàn)C++寫時拷貝”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
本文名稱:怎么實現(xiàn)C++寫時拷貝
網(wǎng)頁URL:http://weahome.cn/article/gcposo.html