日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

                歡迎訪問 生活随笔!

                生活随笔

                當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

                编程问答

                线程安全和可重入函数的联系与区别

                發(fā)布時(shí)間:2023/12/20 编程问答 29 豆豆
                生活随笔 收集整理的這篇文章主要介紹了 线程安全和可重入函数的联系与区别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

                ?

                1、????線程安全:

                線程安全是多線程訪問時(shí),采用了加鎖機(jī)制,當(dāng)一個(gè)線程訪問該類的某個(gè)數(shù)據(jù)時(shí),進(jìn)行保護(hù),其他線程不能進(jìn)行訪問直到該線程訪問完,其他線程才可以使用。不會(huì)出現(xiàn)數(shù)據(jù)不一致或數(shù)據(jù)污染。

                線程不安全就是不提供數(shù)據(jù)訪問保護(hù),有可能出現(xiàn)多個(gè)線程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)。

                四類線程不安全函數(shù):

                (1)不保護(hù)共享變量的函數(shù)(線程不安全):將這類函數(shù)轉(zhuǎn)化為線程安全的,相對比較容易:可利用像P和V操作這樣的同步操作來保護(hù)共享變量。優(yōu)點(diǎn)在于調(diào)用程序中不需要做任何修改,缺點(diǎn)是同步操作將減慢程序的運(yùn)行時(shí)間。

                (2)保持跨越多個(gè)調(diào)用的狀態(tài)函數(shù)(線程不安全):一個(gè)偽隨機(jī)數(shù)生成器就是這類的不安全函數(shù)的簡單例子。

                ?

                usigned int next = 1;

                int rand(){

                ?????? next= next * 1103515245 + 12345;

                ?????? return(usigned int)(next/65536)%32768;

                }

                void srand(usigned int seed){

                next= seed;

                }

                rand 函數(shù)是線程不安全的,因?yàn)楫?dāng)前調(diào)用的結(jié)果依賴于前次調(diào)用的中間結(jié)果。當(dāng)我們調(diào)用srand為rand設(shè)置一個(gè)種子之后,我們反復(fù)從一個(gè)種子中調(diào)用rand,我們能夠預(yù)期一個(gè) 可重復(fù)的隨機(jī)數(shù)字序列。但如果多個(gè)線程同時(shí)調(diào)用rand函數(shù),那假設(shè)就不成立。使用rand函數(shù)變?yōu)榫€程安全的唯一方式是重寫它,使得它不再使用任何靜態(tài)數(shù)據(jù),取而代之的依靠調(diào)用者在參數(shù)中傳遞狀態(tài)信息。缺點(diǎn)要被迫改寫調(diào)用程序的代碼。

                (3)返回指向靜態(tài)變量指針的函數(shù):

                某些函數(shù)(如gethostbyname)將計(jì)算結(jié)果放在靜態(tài)結(jié)構(gòu)中,并返回一個(gè)指向這個(gè)結(jié)構(gòu)的指針。如果我們從并發(fā)線程中調(diào)用這些函數(shù),那么將可能發(fā)生災(zāi)難,因?yàn)檎诒灰粋€(gè)線程使用的結(jié)果會(huì)被另一個(gè)線程悄悄地覆蓋了。

                有兩種方法來處理這類線程不安全函數(shù)。一種是選擇重寫函數(shù),使得調(diào)用者傳遞存放結(jié)果的結(jié)構(gòu)地址。這就消除了所有共享數(shù)據(jù),但是它要求程序員還要改寫調(diào)用者的代碼。

                如果線程不安全函數(shù)是難以修改或不可修改的(例如,它是從一個(gè)庫中鏈接過來的),那么另外一種選擇就是使用lock-and-copy(加鎖-拷貝)技術(shù)。這個(gè)概念將線程不安全函數(shù)與互斥鎖聯(lián)系起來。在每個(gè)調(diào)用位置,對互斥鎖加鎖,調(diào)用函數(shù)不安全函數(shù),動(dòng)態(tài)地為結(jié)果非配存儲(chǔ)器,拷貝函數(shù)返回的結(jié)果到這個(gè)存儲(chǔ)器位置,然后對互斥鎖解鎖。一個(gè)吸引人的變化是定義了一個(gè)線程安全的封裝(wrapper)函數(shù),它執(zhí)行l(wèi)ock-and-copy,然后調(diào)用這個(gè)封轉(zhuǎn)函數(shù)來取代所有線程不安全的函數(shù)。例如下面的gethostbyname的線程安全函數(shù)。

                struct hostent* gethostbyname_ts(char* host){

                struct hostent* shared,* unsharedp;

                ??? unsharedp =Malloc(sizeof(struct hostent));

                P(&mutex)

                Hared =gethostbyname(hostname);*unsharedp =* shared;

                V(&mutex);returnunsharedp;

                }

                ?

                (4)調(diào)用線程不安全函數(shù)的函數(shù)

                如果函數(shù)f調(diào)用線程不安全函數(shù)g,那么f就是線程不安全的嗎?不一定。如果g是類2類函數(shù),即依賴于跨越多次調(diào)用的狀態(tài),那么f也是不安全的,而且除了重寫g以外,沒有什么辦法。然而如果g是第1類或者第3類函數(shù),那么只要用互斥鎖保護(hù)調(diào)用位置和任何得到的共享數(shù)據(jù),f可能仍然是線程安全的。比如上面的gethostbyname_ts。

                ?

                ?

                ?

                2、????可重入函數(shù):

                函數(shù)被不同的控制流程調(diào)?用,有可能在第一次調(diào)用還沒返回時(shí)就再次進(jìn)入該函 數(shù),這稱為重入,insert函數(shù)訪問一個(gè)全局鏈表,有可能因?yàn)橹厝攵斐慑e(cuò)亂,像這樣的函數(shù)稱為 不可重入函數(shù),反之,如果一個(gè)函數(shù)只訪問自己的局部變量或參數(shù),則稱為可重入(Reentrant)函數(shù)。

                ?

                ?可重入特點(diǎn)

                由于可重入函數(shù)多次調(diào)用不會(huì)出錯(cuò),因此可重入函數(shù)不用擔(dān)心數(shù)據(jù)會(huì)被破壞。可重入函數(shù)任何時(shí)候都可以被中斷,一段時(shí)間后又可以運(yùn)行,而相應(yīng)的數(shù)據(jù)不會(huì)丟失。可重入函數(shù)只使用局部變量,即保存在CPU寄存器或者堆棧中;或者如果使用全局變量時(shí),則要對全局變量予以保護(hù)。

                ?

                ?不可重入特點(diǎn)

                如果一個(gè)函數(shù)符合以下條件之一的,則是不可重入的:

                (1)調(diào)用了malloc/free函數(shù),因?yàn)閙alloc函數(shù)是用全局鏈表來管理堆的。

                (2)調(diào)用了標(biāo)準(zhǔn)I/O庫函數(shù),標(biāo)準(zhǔn)I/O庫的很多實(shí)現(xiàn)都以不可重入的方式使用全局數(shù)據(jù)結(jié)構(gòu)

                (3)可重入體內(nèi)使用了靜態(tài)的數(shù)據(jù)結(jié)構(gòu)。

                ?

                3、????可重入函數(shù)與線程安全的關(guān)系:


                可重入函數(shù)與線程安全的區(qū)別與聯(lián)系:

                (1)線程安全是在多個(gè)線程情況下引發(fā)的,而可重入函數(shù)可以在只有一個(gè)線程的情況下來說。

                (2)線程安全不一定是可重入的,而可重入函數(shù)則一定是線程安全的。

                (3)如果一個(gè)函數(shù)中有全局或靜態(tài)變量,那么這個(gè)函數(shù)既不是線程安全也不是可重入的。如果我們對它加以改進(jìn),在訪問全局或靜態(tài)變量時(shí)使用互斥量或信號(hào)量等方式加鎖,則可以使它變成線程安全的,但此時(shí)它仍然是不可重入的,如果將函數(shù)中的全局或靜態(tài)變量去掉,改成函數(shù)參數(shù)等其他形式,則有可能使函數(shù)變成既線程安全,又可重入。

                (4)如果將對臨界資源的訪問加上鎖,則這個(gè)函數(shù)是線程安全的,但如果這個(gè)重入函數(shù)若鎖還未釋放則會(huì)產(chǎn)生死鎖,因此是不可重入的。

                (5)線程安全函數(shù)能夠使不同的線程訪問同一塊地址空間,而可重入函數(shù)要求不同的執(zhí)行流對數(shù)據(jù)的操作互不影響使結(jié)果是相同的。

                (6)strtok函數(shù)是既不可重入的,也不是線程安全的;加鎖的strtok不是可重入的,但線程安全;而strtok_r既是可重入的,也是線程安全的。

                ?

                注:

                1.可重入概念只和函數(shù)訪問的變量類型有關(guān),和是否使用鎖沒有關(guān)系。
                2.而線程安全和鎖的使用關(guān)系密切,很多時(shí)候線程安全是靠鎖來保證的

                ?

                ?

                總結(jié)

                以上是生活随笔為你收集整理的线程安全和可重入函数的联系与区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

                如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。