最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C語(yǔ)言實(shí)現(xiàn)this指針

2022-04-23 13:56 作者:陳偉國(guó)AE  | 我要投稿

this指針作為面向?qū)ο笾械闹匾獧C(jī)制,可以指向當(dāng)前對(duì)象自己的屬性和方法。在之前的C語(yǔ)言實(shí)現(xiàn)面向?qū)ο蟮膶?/a>中,this指針僅僅采用了一個(gè)公用的全局變量來(lái)存儲(chǔ),這種設(shè)計(jì)方法不僅在多處理機(jī)多線程環(huán)境下會(huì)產(chǎn)生問題,甚至在單處理機(jī)環(huán)境下也會(huì)導(dǎo)致問題(中斷)。舉個(gè)例子:

上面的例子中,this函數(shù)同時(shí)被兩個(gè)函數(shù)訪存,且中斷事件導(dǎo)致代碼失去順序性,產(chǎn)生跳轉(zhuǎn),這和多線程輪詢執(zhí)行一樣,必然導(dǎo)致this指針被覆蓋或篡改的問題。

下面來(lái)解決這個(gè)問題:

首先肯定不能用一個(gè)統(tǒng)一的this指針為每個(gè)模塊共享使用,應(yīng)當(dāng)為每個(gè)模塊獨(dú)立創(chuàng)建一個(gè)私有的this指針,說(shuō)到私有,也就是每個(gè)C文件下的this指針是獨(dú)立存在的,不受其他文件的this指針?biāo)绊憽T贑語(yǔ)言中,如果你用常規(guī)方法創(chuàng)建同名的全局變量,會(huì)報(bào)重復(fù)定義的錯(cuò)誤,可以通過添加static關(guān)鍵字來(lái)表示此全局變量存放于靜態(tài)存儲(chǔ)區(qū)中,且只在本文件中可以被訪問,其他C文件無(wú)法訪問到此變量,如下例:

這樣就解決了每個(gè)模塊私有訪問自己的this指針的問題。


如何保證在多線程或中斷環(huán)境下,this指針仍能保證線程安全,下面來(lái)解決第二個(gè)問題:

眾所周知,多線程和中斷之所以能正確的執(zhí)行而不影響其他函數(shù),是因?yàn)樵谔D(zhuǎn)到中斷函數(shù)或線程任務(wù)函數(shù)之前,執(zhí)行了保護(hù)現(xiàn)場(chǎng)工作,即將CPU狀態(tài)寄存器和PC的值保留在當(dāng)前函數(shù)棧中,然后再執(zhí)行中斷函數(shù)或線程任務(wù)。執(zhí)行完畢后,先從??臻g中把之前保存的現(xiàn)場(chǎng)信息還原,再繼續(xù)執(zhí)行。參照上面的流程可知,this指針產(chǎn)生數(shù)據(jù)一致性問題的本質(zhì)原因是沒有做到在函數(shù)調(diào)用時(shí)保存現(xiàn)場(chǎng),在線程任務(wù)中或中斷函數(shù)中產(chǎn)生對(duì)象函數(shù)調(diào)用則將當(dāng)前對(duì)象指針壓入This棧中,在調(diào)用對(duì)象方法時(shí),第一行用于從This棧棧頂彈出自身對(duì)象,此時(shí)棧頂指針將指向上次的this指針,通過這種方式即可實(shí)現(xiàn)this指針的獨(dú)立性。

在對(duì)象調(diào)用自身方法時(shí),先通過setThis(n)操作將當(dāng)前對(duì)象壓入This棧中,再調(diào)用自身方法,在方法中,第一行用于獲取棧頂指針并保存在temp中,即剛才壓入棧中的對(duì)象,隨后的所有對(duì)象操作都通過temp來(lái)調(diào)用。通過棧來(lái)設(shè)計(jì)this指針,在中斷或多線程情況下,假如A執(zhí)行了setThis(a)將當(dāng)前對(duì)象a壓入棧中,但是沒來(lái)得及調(diào)用方法取出棧頂對(duì)象,就被B中斷信號(hào)打斷了,B中斷調(diào)用setThis(b)將b壓入棧中,而后b對(duì)象調(diào)用方法并正確從棧頂彈出自身對(duì)象b,繼續(xù)執(zhí)行方法,中斷函數(shù)執(zhí)行完畢后,回到A任務(wù),此時(shí)A再?gòu)臈m敨@取的對(duì)象正是自己的對(duì)象a。

由于中斷事件是以中斷函數(shù)為單位執(zhí)行,所以在中斷嵌套的情況下,是一級(jí)一級(jí)的從函數(shù)棧中彈出,不存在像多線程輪詢時(shí)的無(wú)序性,即A任務(wù)執(zhí)行了一半又去執(zhí)行B任務(wù),B任務(wù)可能剛開始執(zhí)行一會(huì)又去執(zhí)行C任務(wù),C任務(wù)執(zhí)行了一半又回到A任務(wù).....。而中斷是能確保最高級(jí)別中斷函數(shù)執(zhí)行完畢后再回到上一級(jí)函數(shù)繼續(xù)執(zhí)行,這樣一級(jí)級(jí)向上從函數(shù)棧中彈出。因此以上操作在中斷情況下能正確執(zhí)行,下面來(lái)討論多線程輪詢情況下的解決辦法。


由于多線程情況比較復(fù)雜,舉一個(gè)例子來(lái)說(shuō)明上述方法在多線程情況下的問題和解決方案。

例:現(xiàn)有3個(gè)線程A,B,C,以及三個(gè)同類對(duì)象a,b,c

(1).A線程首先調(diào)用setThis(a)操作將a對(duì)象壓入This棧

(2).沒等a對(duì)象調(diào)用方法從This棧頂獲取自身對(duì)象,A線程時(shí)間片消耗完畢,切換到B線程執(zhí)行

(3).B線程執(zhí)行setThis(b)操作將b對(duì)象壓入This棧,此時(shí)This棧中元素為:b,a

(4).b對(duì)象調(diào)用方法,第一行先從棧頂彈出自身對(duì)象后,再繼續(xù)執(zhí)行方法

(5).B線程方法執(zhí)行了一半,時(shí)間片消耗完畢,切換到C線程執(zhí)行,此時(shí)This棧中的元素為:a

(6).C線程執(zhí)行setThis(c)將c對(duì)象壓入This棧,此時(shí)This棧中元素為:c,a

(7).在c對(duì)象調(diào)用方法從This棧頂彈出自身對(duì)象之前,線程C時(shí)間片消耗完畢,切換到A線程執(zhí)行,此時(shí)This棧中的元素為:c,a

(8).A線程繼續(xù)執(zhí)行,a對(duì)象調(diào)用方法,第一行從This棧頂彈出對(duì)象,但此時(shí)彈出的對(duì)象是c,并非自身對(duì)象,這必然導(dǎo)致a對(duì)象調(diào)用方法出錯(cuò)。

那么如何解決這個(gè)問題呢,其實(shí)十分簡(jiǎn)單,熟悉線程安全的開發(fā)者立刻就想到了信號(hào)量。這里使用一個(gè)同步信號(hào)量來(lái)保證setThis()操作和對(duì)象調(diào)用方法從This棧彈棧操作這兩個(gè)操作成為原子操作,要么兩個(gè)操作都執(zhí)行,要么都不執(zhí)行。在setThis()函數(shù)壓棧時(shí),flag置為true,在方法調(diào)用的第一行彈棧操作時(shí),將flag置為false。如果A線程執(zhí)行了setThis(a)將對(duì)象a壓入棧中,并置flag為true,然后切換到B線程,執(zhí)行setThis(b)時(shí),執(zhí)行while(flag);等待鎖被釋放,即忙等,當(dāng)然也可直接yield(),主動(dòng)放棄此輪CPU調(diào)度。線程B忙等到時(shí)間片消費(fèi)完畢或主動(dòng)放棄CPU調(diào)度后,切換回A線程,A線程繼續(xù),調(diào)用方法從This棧中彈出a對(duì)象,并置flag為false,a繼續(xù)執(zhí)行方法,A線程時(shí)間片耗盡后切換到B線程,B線程繼續(xù)while(flag),由于此時(shí)flag為false,可以正常操作。


總結(jié)下兩種情況:

中斷:無(wú)需上鎖,可正確入棧出棧,CPU利用率高

多線程:需要上鎖,同類對(duì)象忙等情況下,CPU利用率低。yield()情況下,CPU利用率高。

不過不用擔(dān)心效率問題,上面的例子為多線程切換的極端情況,很少會(huì)發(fā)生,一般情況下線程時(shí)間片為毫秒級(jí)別,完全能夠保證對(duì)象入棧和出棧能在時(shí)間片周期內(nèi)完成,即不會(huì)產(chǎn)生等待。而在上述的極端情況下,A線程在時(shí)間片結(jié)束的那一刻調(diào)用了setThis將對(duì)象a入棧,但沒來(lái)得及調(diào)用對(duì)象方法從棧中獲取對(duì)象a,就切換到B線程執(zhí)行了,此時(shí)B線程如果調(diào)用同類對(duì)象,要么等待,要么主動(dòng)讓出CPU給A線程繼續(xù)執(zhí)行,解開同步鎖。在對(duì)象調(diào)用方法的流程如下:

call()是一個(gè)宏函數(shù),里面執(zhí)行了兩步:

(1) 設(shè)flag=true,調(diào)用setThis(str),將當(dāng)前str對(duì)象壓入String類的This棧中

(2) 調(diào)用.equals("123")方法,方法內(nèi)第一行從This棧棧頂取出str對(duì)象并設(shè)flag=false然后繼續(xù)執(zhí)行方法

可見在對(duì)象調(diào)用方法時(shí),入棧和出棧操作是緊挨著的兩條語(yǔ)句,即flag被置為true后,馬上就執(zhí)行入棧出棧,而入棧和出棧的時(shí)間復(fù)雜度是o(1),也就是在flag置為true后,僅需幾條指令就能完成入棧出棧,并置flag=false。為了再次提升效率,可將pop()函數(shù)改為內(nèi)聯(lián)函數(shù)或宏函數(shù),減少函數(shù)入棧指令和函數(shù)出棧指令對(duì)時(shí)間片的開銷。就像這樣:

可見入棧出??偣簿?條語(yǔ)句,在通過inline修飾,減少了函數(shù)跳轉(zhuǎn)的開銷,保證在絕大多數(shù)情況下不會(huì)出現(xiàn)忙等。

針對(duì)兩種情況的setThis()函數(shù)實(shí)現(xiàn)不一樣,中斷情況下無(wú)需任何判斷,直接入棧,而多線程情況下需要加入while(flag);或if(flag) yield();操作。

下面我將用c語(yǔ)言演示通過棧實(shí)現(xiàn)this的代碼:


封裝基于順序棧的This對(duì)象:

This.h文件:

This.c文件:


創(chuàng)建String類測(cè)試This對(duì)象:

MyString.h文件:

MyString.c文件:


在main.c中調(diào)用以測(cè)試結(jié)果:

單線程測(cè)試結(jié)果


下面演示多線程下測(cè)試結(jié)果:

測(cè)試方法:讓多個(gè)線程中的多個(gè)String對(duì)象輸出自己的字符串值,字符串對(duì)象的獲取通過This棧獲取,如果正確輸出,則多線程環(huán)境下無(wú)誤。

測(cè)試正常無(wú)誤,如下視頻所示:

碼字碼了一整天,就當(dāng)復(fù)習(xí)下數(shù)據(jù)結(jié)構(gòu)和操作系統(tǒng)了。像往常一樣,此工程直接分享出來(lái),帶師門可自行測(cè)試和移植優(yōu)化:

鏈接:https://pan.baidu.com/s/15EfFJOFMp7OEawPj5oYl3w?

提取碼:ALYA?


C語(yǔ)言實(shí)現(xiàn)this指針的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
红安县| 桦甸市| 沂水县| 英山县| 新龙县| 紫金县| 佛学| 小金县| 宾川县| 时尚| 恭城| 阿勒泰市| 丰城市| 赤城县| 江华| 射阳县| 洛阳市| 紫云| 深圳市| 中西区| 抚州市| 绍兴县| 广元市| 读书| 广德县| 汝城县| 渝中区| 宁化县| 和平区| 黄石市| 祁阳县| 维西| 黔东| 岳阳县| 无锡市| 山东省| 武隆县| 鸡泽县| 宁南县| 滦南县| 阜阳市|