91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用條件變量的坑有哪些

發布時間:2021-10-26 16:45:18 來源:億速云 閱讀:125 作者:iii 欄目:web開發

本篇內容介紹了“使用條件變量的坑有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

1. 什么是條件變量?

條件變量是多線程程序中用來實現等待和喚醒邏輯常用的方法。通常有wait和notify兩個動作,wait用于阻塞掛起線程A,直到另一個線程B通過通過notify喚醒線程A,喚醒后線程A會繼續運行。

條件變量在多線程中很常用,在有名的生產者和消費者問題中,消費者如何知道生成者是否生產出了可以消費的產品,通過while循環不停的去判斷是否有可消費的產品?眾所周知,死循環極其消耗CPU性能,所以需要使用條件變量來阻塞線程,降低CPU占用率。

2. 條件變量的使用

拿生產者和消費者問題舉例,看下面這段代碼:

std::mutex mutex; std::condition_variable cv; std::vector<int> vec;  void Consume() {   std::unique_lock<std::mutex> lock(mutex);   cv.wait(lock);   std::cout << "consume " << vec.size() << "\n"; }  void Produce() {   std::unique_lock<std::mutex> lock(mutex);   vec.push_back(1);   cv.notify_all();   std::cout << "produce \n"; }  int main() {   std::thread t(Consume);   t.detach();   Produce();   return 0; }

本意是消費者線程阻塞,等待生產者生產數據后去通知消費者線程,這樣消費者線程就可以拿到數據去消費。

但這里有個問題:

如果先執行的Produce(),后執行的Consume(),生產者提前生產出了數據,去通知消費者,但是此時消費者線程如果還沒有執行到wait語句,即線程還沒有處于掛起等待狀態,線程沒有等待此條件變量上,那通知的信號就丟失了,后面Consume()中才執行wait處于等待狀態,但此時生產者已經不會再觸發notify,那消費者線程就會始終阻塞下去,出現bug。

如何解決這個問題呢?可以附加一個判斷條件,就可以解決這種信號丟失問題,見代碼:

std::mutex mutex; std::condition_variable cv; std::vector<int> vec;  void Consumer() {   std::unique_lock<std::mutex> lock(mutex);   if (vec.empty()) { // 加入此判斷條件       cv.wait(lock);   }   std::cout << "consumer " << vec.size() << "\n"; }  void Produce() {   std::unique_lock<std::mutex> lock(mutex);   vec.push_back(1);   cv.notify_all();   std::cout << "produce \n"; }  int main() {   std::thread t(Consumer);   t.detach();   Produce();   return 0; }

通過增加附加條件可以解決信號丟失的問題,但這里還有個地方需要注意,消費者線程處于wait阻塞狀態時,即使沒有調用notify,操作系統也會有一些概率會喚醒處于阻塞的線程,使其繼續執行下去,這就是虛假喚醒問題,當出現了虛假喚醒后,消費者線程繼續執行,還是沒有可以消費的數據,出現了bug。

那怎么解決虛假喚醒的問題呢,可以在線程由阻塞狀態被喚醒后繼續判斷附加條件,看是否滿足喚醒的條件,如果滿足則繼續執行,如果不滿足,則繼續去等待,體現在代碼中,即將if判斷改為while循環判斷,見代碼:

std::mutex mutex; std::condition_variable cv; std::vector<int> vec;  void Consumer() {   std::unique_lock<std::mutex> lock(mutex);   while (vec.empty()) { // 將if改為while       cv.wait(lock);   }   std::cout << "consumer " << vec.size() << "\n"; }  void Produce() {   std::unique_lock<std::mutex> lock(mutex);   vec.push_back(1);   cv.notify_all();   std::cout << "produce \n"; }  int main() {   std::thread t(Consumer);   t.detach();   Produce();   return 0; }

看到這里相信你已經明白條件變量的使用啦,需要使用while循環附加判斷條件來解決條件變量的信號丟失和虛假喚醒問題。

3. 有沒有更簡單的“避坑”方式

難道我們每次都必須要使用while循環和附加條件來操作條件變量嗎?這豈不是很麻煩?

NO!

在C++中其實有更好的封裝,只需要調用wait函數時,在參數中直接添加附加條件就好了,內部已經做好了while循環判斷,直接使用即可,見代碼:

std::mutex mutex; std::condition_variable cv; std::vector<int> vec;  void Consumer() {   std::unique_lock<std::mutex> lock(mutex);   cv.wait(lock, [&](){ return !vec.empty(); }); // 這里可以直接使用C++的封裝   std::cout << "consumer " << vec.size() << "\n"; }  void Produce() {   std::unique_lock<std::mutex> lock(mutex);   vec.push_back(1);   cv.notify_all();   std::cout << "produce \n"; }  int main() {   std::thread t(Consumer);   t.detach();   Produce();   return 0; }

但在C語言中就沒辦法啦,大家只能自己做一層封裝啦。

4. 為什么條件變量需要和鎖配合使用?

為什么叫條件變量呢?

因為內部是通過判斷及修改某個全局變量來決定線程的阻塞與喚醒,多線程操作同一個變量肯定需要加鎖來使得線程安全。同時,一個簡單的wait函數調用內部會很復雜的,有可能線程A調用了wait函數但是還沒有進入到wait阻塞等待前,另一個線程B在此時卻調用了notify函數,此時nofity的信號就丟失啦,如果加了鎖,線程B必須等待線程A釋放了鎖并進入了等待狀態后才可以調用notify,繼而防止信號丟失。

關于條件變量就介紹到這里,希望大家能有所收獲,平時使用過程中可以避掉條件變量的坑。

“使用條件變量的坑有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

邹平县| 潞城市| 封丘县| 平乡县| 湘乡市| 莱阳市| 东海县| 托克托县| 盐山县| 富宁县| 渝中区| 广安市| 威远县| 黄大仙区| 东兰县| 荃湾区| 即墨市| 陇川县| 和林格尔县| 濮阳市| 威信县| 连云港市| 阿坝县| 大冶市| 尼玛县| 雅江县| 永寿县| 紫金县| 咸宁市| 禹城市| 闻喜县| 卢龙县| 黔西县| 莱芜市| 黔西| 双柏县| 确山县| 七台河市| 邮箱| 绥宁县| 伊宁县|