多執行緒下的返回值優化陷阱

2021-04-20 16:50:36 字數 2225 閱讀 9390

「函式的返回值優化」是我們對程式的乙個常見優化手段。只要可能,我們都應該返回物件的有效引用,而不是重新生成乙個臨時物件。但是,也許這種想法在多執行緒裡需要更仔細的斟酌一下。

我從乙個簡單例子講起:

template

class fdmap

else}}

t get(int fd) const

};這裡

fdmap

是乙個把

int對映到

t物件的型別,採用

std::vector

作為底層容器。它所做的工作很簡單:在需要的時候擴充容器

vec_

;如果訪問超過了範圍,返回

t的預設值。 如果

fdmap

要在多執行緒下工作,那麼我們需要加一點**,進行必要的同步:

template

class fdmap

else}}

t get(int fd) const

return t();}};

其中mutex

是任意執行緒同步型別;

guard

是對應的範圍保衛型別,在構造的時候鎖住

mutex_

,析構的時候解鎖。到目前為止,

fdmap

類非常完美,沒有任何問題。

在實際應用中,我們可能把

fdmap

用於關聯

socket fd

和對應的客戶端連線物件(例如

clientdata

),於是可能的例項化是

fdmap。

不過有經驗的程式設計師馬上會看出,直接在

fdmap

裡儲存clientdata

指標是不行的。如果某個執行緒

get到了乙個fd的

clientdata

指標,而另乙個執行緒卻試圖關閉這個

fd連線,那麼

clientdata

物件是釋放掉,還是繼續有效?如果釋放了

clientdata

物件,那麼前乙個執行緒隨後的訪問就會失效;如果繼續保留

clientdata

物件,那麼誰也不知道該在何時釋放它了,就會記憶體洩漏。

正確的做法是,在

fdmap

裡儲存clientdata

的智慧型指標,那麼哪個執行緒都不需要特意釋放

clientdata

物件,智慧型指標會在適當的時候處理。為了保險,我們決定使用

boost::shared_ptr

,因為大家都認為它是正確的。 ok

,我們有了乙個設計完美,執行正確的

fdmap

,完整的例項化是:

fdmap>

終於有一天,我們需要優化**,於是我們重新審視上面的**。

get函式!是的,它的返回值是否可以優化?因為對於智慧型指標,即使是拷貝建構函式都是昂貴的,能夠減少乙個臨時物件的構造,對於我們的確太誘人了。

但是有乙個明顯的問題:當

fd不在範圍內的時候,返回誰的引用?且看下面的實現。

下面是我們的「優化」:

const t & get(int fd) const

return def;

}通過增加乙個區域性靜態常量

def,解決了返回預設引用的問題。如果

fd在範圍內,那麼返回

vec_

裡的物件引用,是沒有問題的。

但是當我再次執行這個「優化版」的時候,不幸的是,一天之後程式崩潰了!怎麼回事?我檢查了所有用到

get函式的地方:

boost::shared_ptrpclient = fdmap.get(fd);

這樣的**實在看不出有什麼問題,而檢查

get函式的實現,也沒有發現任何問題!

事實上,問題是這樣的:

仔細分析

get函式的操作,可以發現,在「

return vec_[fd];

」之後,

fdmap

內部的鎖已經解開了,而此時呼叫執行緒得到的還是

fdmap::vec_[fd]

物件的引用,於是接下來給

pclient

賦值的操作就是乙個沒有任何保護的過程。如果在把這個引用賦值給

pclient

的過程中,

fdmap::vec_[fd]

沒有被任何其他執行緒更改,那麼一切正常;否則,程式就可能崩潰!

明白了這個例子,相信大家在以後的優化過程中,會更謹慎的處理多執行緒下的**。

多執行緒返回值

多執行緒返回值,避免阻塞提高效率。public class callabledemo1implements callable system.out.println callabledemo1 end system.out.println thread1test.ct thread1test.ct.c...

多執行緒處理返回值

說了很多廢話,只是希望自己警醒,希望認同上述觀點的人同樣能感受到那些每天看凌晨三點太陽的人的壓力,其他不認同的人大概可以跳過直接看下面的內容。本文要寫的內容是關於執行緒,工作中有些寫業務 的開發這塊用得比較少,但是面試時面試官總喜歡問多執行緒相關問題,例如下面這些 1 什麼是執行緒 2 怎麼樣實現多...

Python多執行緒獲取返回值

在使用多執行緒的時候難免想要獲取其操作完的返回值進行其他操作,下面的方法以作參考 一,首先重寫threading類,使其滿足呼叫特定的方法獲取其返回值 import threading class mythread threading.thread 重寫多執行緒,使其能夠返回值 def init s...