在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

為何需要CMWQ?CMWQ如何解決問題的呢?

Linux閱碼場 ? 來源:未知 ? 作者:李倩 ? 2018-08-20 14:47 ? 次閱讀

一、前言

一種新的機制出現的原因往往是為了解決實際的問題,雖然linux kernel中已經提供了workqueue的機制,那么為何還要引入cmwq呢?也就是說:舊的workqueue機制存在什么樣的問題?在新的cmwq又是如何解決這些問題的呢?它接口是如何呈現的呢(驅動工程師最關心這個了)?如何兼容舊的驅動呢?本文希望可以解開這些謎題。

本文的代碼來自linux kernel 4.0。

二、為何需要CMWQ?

內核中很多場景需要異步執行環境(在驅動中尤其常見),這時候,我們需要定義一個work(執行哪一個函數)并掛入workqueue。處理該work的線程叫做worker,不斷的處理隊列中的work,當處理完畢后則休眠,隊列中有work的時候就醒來處理,如此周而復始。一切看起來比較完美,問題出在哪里呢?

(1)內核線程數量太多。如果沒有足夠的內核知識,程序員有可能會錯誤的使用workqueue機制,從而導致這個機制被玩壞。例如明明可以使用default workqueue,偏偏自己創建屬于自己的workqueue,這樣一來,對于那些比較大型的系統(CPU個數比較多),很可能內核啟動結束后就耗盡了PID space(default最大值是65535),這種情況下,你讓user space的程序情何以堪?雖然default最大值是可以修改的,從而擴大PID space來解決這個問題,不過系統太多的task會對整體performance造成負面影響。

(2)盡管消耗了很多資源,但是并發性如何呢?我們先看single threaded的workqueue,這種情況完全沒有并發的概念,任何的work都是排隊執行,如果正在執行的work很慢,例如4~5秒的時間,那么隊列中的其他work除了等待別無選擇。multi threaded(更準確的是per-CPU threaded)情況當然會好一些(畢竟多消耗了資源),但是對并發仍然處理的不是很好。對于multi threaded workqueue,雖然創建了thread pool,但是thread pool的數目是固定的:每個oneline的cpu上運行一個,而且是嚴格的綁定關系。也就是說本來線程池是一個很好的概念,但是傳統workqueue上的線程池(或者叫做worker pool)卻分割了每個線程,線程之間不能互通有無。例如cpu0上的worker thread由于處理work而進入阻塞狀態,那么該worker thread處理的work queue中的其他work都阻塞住,不能轉移到其他cpu上的worker thread去,更有甚者,cpu0上隨后掛入的work也接受同樣的命運(在某個cpu上schedule的work一定會運行在那個cpu上),不能去其他空閑的worker thread上執行。由于不能提供很好的并發性,有些內核模塊(fscache)甚至自己創建了thread pool(slow work也曾經短暫的出現在kernel中)。

(3)dead lock問題。我們舉一個簡單的例子:我們知道,系統有default workqueue,如果沒有特別需求,驅動工程師都喜歡用這個workqueue。我們的驅動模塊在處理release(userspace close該設備)函數的時候,由于使用了workqueue,那么一般會flush整個workqueue,以便確保本driver的所有事宜都已經處理完畢(在close的時候很有可能有pending的work,因此要flush),大概的代碼如下:

flush work是一個長期過程,因此很有可能被調度出去,這樣調用close的進程被阻塞,等到keventd_wq這個內核線程組完成flush操作后就會wakeup該進程。但是這個default workqueue使用很廣,其他的模塊也可能會schedule work到該workqueue中,并且如果這些模塊的work也需要獲取鎖A,那么就會deadlock(keventd_wq阻塞,再也無法喚醒等待flush的進程)。解決這個問題的方法是創建多個workqueue,但是這樣又回到了內核線程數量大多的問題上來。

我們再看一個例子:假設某個驅動模塊比較復雜,使用了兩個work struct,分別是A和B,如果work A依賴 work B的執行結果,那么,如果這兩個work都schedule到一個worker thread的時候就出現問題,由于worker thread不能并發的執行work A和work B,因此該驅動模塊會死鎖。Multi threaded workqueue能減輕這個問題,但是無法解決該問題,畢竟work A和work B還是有機會調度到一個cpu上執行。造成這些問題的根本原因是眾多的work競爭一個執行上下文導致的。

(4)二元化的線程池機制。基本上workqueue也是thread pool的一種,但是創建的線程數目是二元化的設定:要么是1,要么是number of CPU,但是,有些場景中,創建number of CPU太多,而創建一個線程又太少,這時候,勉強使用了single threaded workqueue,但是不得不接受串行處理work,使用multi threaded workqueue吧,占用資源太多。二元化的線程池機制讓用戶無所適從。

三、CMWQ如何解決問題的呢?

1、設計原則。在進行CMWQ的時候遵循下面兩個原則:

(1)和舊的workqueue接口兼容。

(2)明確的劃分了workqueue的前端接口和后端實現機制。CMWQ的整體架構如下:

對于workqueue的用戶而言,前端的操作包括二種,一個是創建workqueue。可以選擇創建自己的workqueue,當然也可以不創建而是使用系統缺省的workqueue。另外一個操作就是將指定的work添加到workqueue。在舊的workqueue機制中,workqueue和worker thread是密切聯系的概念,對于single workqueue,創建一個系統范圍的worker thread,對于multi workqueue,創建per-CPU的worker thread,一切都是固定死的。針對這樣的設計,我們可以進一步思考其合理性。workqueue用戶的需求就是一個異步執行的環境,把創建workqueue和創建worker thread綁定起來大大限定了資源的使用,其實具體后臺是如何處理work,是否否啟動了多個thread,如何管理多個線程之間的協調,workqueue的用戶并不關心。

基于這樣的思考,在CMWQ中,將這種固定的關系被打破,提出了worker pool這樣的概念(其實就是一種thread pool的概念),也就是說,系統中存在若干worker pool,不和特定的workqueue關聯,而是所有的workqueue共享。用戶可以創建workqueue(不創建worker pool)并通過flag來約束掛入該workqueue上work的處理方式。workqueue會根據其flag將work交付給系統中某個worker pool處理。例如如果該workqueue是bounded類型并且設定了high priority,那么掛入該workqueue的work將由per cpu的highpri worker-pool來處理。

讓所有的workqueue共享系統中的worker pool,即減少了資源的浪費(沒有創建那么多的kernel thread),又保證了靈活的并發性(worker pool會根據情況靈活的創建thread來處理work)。

3、如何解決線程數目過多的問題?

在CMWQ中,用戶可以根據自己的需求創建workqueue,但是已經和后端的線程池是否創建worker線程無關了,是否創建新的work線程是由worker線程池來管理。系統中的線程池包括兩種:

(1)和特定CPU綁定的線程池。這種線程池有兩種,一種叫做normal thread pool,另外一種叫做high priority thread pool,分別用來管理普通的worker thread和高優先級的worker thread,而這兩種thread分別用來處理普通的和高優先級的work。這種類型的線程池數目是固定的,和系統中cpu的數目相關,如果系統有n個cpu,如果都是online的,那么會創建2n個線程池。

(2)unbound 線程池,可以運行在任意的cpu上。這種thread pool是動態創建的,是和thread pool的屬性相關,包括該thread pool創建worker thread的優先級(nice value),可以運行的cpu鏈表等。如果系統中已經有了相同屬性的thread pool,那么不需要創建新的線程池,否則需要創建。

OK,上面講了線程池的創建,了解到創建workqueue和創建worker thread這兩個事件已經解除關聯,用戶創建workqueue僅僅是選擇一個或者多個線程池而已,對于bound thread pool,每個cpu有兩個thread pool,關系是固定的,對于unbound thread pool,有可能根據屬性動態創建thread pool。那么worker thread pool如何創建worker thread呢?是否會數目過多呢?

缺省情況下,創建thread pool的時候會創建一個worker thread來處理work,隨著work的提交以及work的執行情況,thread pool會動態創建worker thread。具體創建worker thread的策略為何?本質上這是一個需要在并發性和系統資源消耗上進行平衡的問題,CMWQ使用了一個非常簡單的策略:當thread pool中處于運行狀態的worker thread等于0,并且有需要處理的work的時候,thread pool就會創建新的worker線程。當worker線程處于idle的時候,不會立刻銷毀它,而是保持一段時間,如果這時候有創建新的worker的需求的時候,那么直接wakeup idle的worker即可。一段時間過去仍然沒有事情處理,那么該worker thread會被銷毀。

4、如何解決并發問題?

我們用某個cpu上的bound workqueue來描述該問題。假設有A B C D四個work在該cpu上運行,缺省的情況下,thread pool會創建一個worker來處理這四個work。在舊的workqueue中,A B C D四個work毫無疑問是串行在cpu上執行,假設B work阻塞了,那么C D都是無法執行下去,一直要等到B解除阻塞并執行完畢。

對于CMWQ,當B work阻塞了,thread pool可以感知到這一事件,這時候它會創建一個新的worker thread來處理C D這兩個work,從而解決了并發的問題。由于解決了并發問題,實際上也解決了由于競爭一個execution context而引入的各種問題(例如dead lock)。

四、接口API

1、初始化work的接口保持不變,可以靜態或者動態創建work。

2、調度work執行也保持和舊的workqueue一致。

3、創建workqueue。和舊的create_workqueue接口不同,CMWQ采用了alloc_workqueue這樣的接口符號,相關的接口定義如下:

在描述這些workqueue的接口之前,我們需要準備一些workqueue flag的知識。

標有WQ_UNBOUND這個flag的workqueue說明其work的處理不需要綁定在特定的CPU上執行,workqueue需要關聯一個系統中的unbound worker thread pool。如果系統中能找到匹配的線程池(根據workqueue的屬性(attribute)),那么就選擇一個,如果找不到適合的線程池,workqueue就會創建一個worker thread pool來處理work。

WQ_FREEZABLE是一個和電源管理相關的內容。在系統Hibernation或者suspend的時候,有一個步驟就是凍結用戶空間的進程以及部分(標注freezable的)內核線程(包括workqueue的worker thread)。標記WQ_FREEZABLE的workqueue需要參與到進程凍結的過程中,worker thread被凍結的時候,會處理完當前所有的work,一旦凍結完成,那么就不會啟動新的work的執行,直到進程被解凍。

和WQ_MEM_RECLAIM這個flag相關的概念是rescuer thread。前面我們描述解決并發問題的時候說到:對于A B C D四個work,當正在處理的B work被阻塞后,worker pool會創建一個新的worker thread來處理其他的work,但是,在memory資源比較緊張的時候,創建worker thread未必能夠成功,這時候,如果B work是依賴C或者D work的執行結果的時候,系統進入dead lock。這種狀態是由于不能創建新的worker thread導致的,如何解決呢?對于每一個標記WQ_MEM_RECLAIM flag的work queue,系統都會創建一個rescuer thread,當發生這種情況的時候,C或者D work會被rescuer thread接手處理,從而解除了dead lock。

WQ_HIGHPRI說明掛入該workqueue的work是屬于高優先級的work,需要高優先級(比較低的nice value)的worker thread來處理。

WQ_CPU_INTENSIVE這個flag說明掛入該workqueue的work是屬于特別消耗cpu的那一類。為何要提供這樣的flag呢?我們還是用老例子來說明。對于A B C D四個work,B是cpu intersive的,當thread正在處理B work的時候,該worker thread一直執行B work,因為它是cpu intensive的,特別吃cpu,這時候,thread pool是不會創建新的worker的,因為當前還有一個worker是running狀態,正在處理B work。這時候C Dwork實際上是得不到執行,影響了并發。

了解了上面的內容,那么基本上alloc_workqueue中flag參數就明白了,下面我們轉向max_active這個參數。系統不能允許創建太多的thread來處理掛入某個workqueue的work,最多能創建的線程數目是定義在max_active參數中。

除了alloc_workqueue接口API之外,還可以通過alloc_ordered_workqueue這個接口API來創建一個嚴格串行執行work的一個workqueue,并且該workqueue是unbound類型的。create_*的接口都是為了兼容過去接口而設立的,大家可以自行理解,這里就不多說了。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8598

    瀏覽量

    151159
  • 驅動
    +關注

    關注

    12

    文章

    1840

    瀏覽量

    85293

原文標題:郭健: currency Managed Workqueue(CMWQ)概述

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    開關電源電路中為何需要串聯小電阻

    開關電源電路中為何需要串聯小電阻,起什么作用,在電源中會見到阻值特別小的電阻,通常是0.5-2.2歐姆,它們分別在不同的位置,起到不同的作用。 在電源輸入端會串聯一顆2.2歐左右的電阻,這樣
    的頭像 發表于 11-19 13:40 ?1625次閱讀
    開關電源電路中<b class='flag-5'>為何需要</b>串聯小電阻

    為何需要進行仿真?

    為何需要進行仿真? Simulation and Prototyping in the Design ProcessIn order to ensure a successful circuit
    發表于 07-01 10:51

    請問這個函數為何需要釋放內存?

    (10,150,100,16,16,"TMR1 STOP! ");}} }為何需要 釋放內存呀?去掉后,程序也運行正常!myfree(SRAMIN,pbuf);//釋放內存
    發表于 07-11 04:35

    為什么需要這個跳線開關?

    看過“FLEX PCI Development Board”的參考設計原理圖, 它利用了條線開關選擇配置方式. 既然兩種配置方式管腳并沒有公用, 為何需要這個跳線開關
    發表于 09-04 05:55

    柵極驅動器是什么,為何需要柵極驅動器?

    為何需要柵極驅動器柵極驅動器的關鍵參數
    發表于 12-25 06:15

    物聯網為何需要開源操作系統?物聯網開源操作系統有哪幾種?

    操作系統是什么?操作系統通常具有哪些功能?什么是開源操作系統?開源操作系統的優勢有哪些?物聯網為何需要開源操作系統?物聯網開源操作系統有哪幾種?
    發表于 06-16 06:37

    什么是步進電機?步進電機為何需要驅動電路?

    什么是步進電機?步進電機為何需要驅動電路?步進電機的有哪幾個概念?分別是什么?
    發表于 06-30 07:05

    為何需要PIDSTM32CubeMX創建STM32源代碼

    PID以及為何需要PIDSTM32CubeMX創建STM32源代碼1、何為PID以及為何需要PID??以下是PID控制的整體框圖,過程描述為:設定一個輸出目標,反饋系統傳回輸出值,如與目標不一致,則存在一個誤差,PID根據此誤差調整輸入值,直至輸出達到設定值。??疑問:那
    發表于 08-10 07:49

    單片機的啟動代碼干了些什么工作,為何需要它?

    。。。扯遠了!其實電腦本身就是從單片機而來,那么單片機也是有啟動代碼的,只是我們絕大部分情況不去關心它。啟動代碼究竟都干了些什么工作,為何需要它?想想你在c語言中用到了什么東西,而這些東西卻是拿來...
    發表于 11-22 07:40

    為何電機起動時閘刀開關的熔體會熔斷?如何解決?

    為何電機起動時閘刀開關的熔體熔斷?如何解決?本文小編就給大家來分析下原因及解決方法。
    的頭像 發表于 12-14 22:46 ?904次閱讀

    工業自動化為何需要機器視覺?工業自動化是否需工控計算機?

    工業自動化技術日益成熟,大家對于工業自動化均有所耳聞。但是,大家對工業自動化真的了解嗎?工業自動化中為何使用機器視覺?工業自動化中又為何需使用工控計算機?對于這些問題,大家心中是否具有明確答案?如果你對這些問題具有疑惑,不妨在本文中尋求答案哦
    的頭像 發表于 12-24 20:23 ?795次閱讀

    為何電機起動時閘刀開關的熔體熔斷?如何解決?

    為何電機起動時閘刀開關的熔體熔斷?如何解決?本文小編就給大家來分析下原因及解決方法。
    發表于 02-05 07:08 ?5次下載
    <b class='flag-5'>為何</b>電機起動時閘刀開關的熔體熔斷?如<b class='flag-5'>何解</b>決?

    什么是運輸節電模式 為何需要

    。 圖 1:拉動電池供電產品上的拉片 什么是運輸節電模式,為何需要它? 運輸節電模式是產品消耗最低電池電流的狀態。消費者希望在購買電池供電產品后能夠立即使用它們。這意味著電池在運輸期間
    的頭像 發表于 01-15 10:20 ?1560次閱讀

    何謂沖擊電流?為何需要沖擊電流防止電路?

    何謂沖擊電流?為何需要沖擊電流防止電路? 沖擊電流是指在電路中瞬時地流過較高的電流。它通常在開關電源、電機、變壓器等設備啟動或停止時發生。這種電流瞬間產生,具有高峰值和短時間的特征。如果沒有采取措施
    的頭像 發表于 10-27 14:24 ?5264次閱讀

    何為PID?為何需要PID?PID能達到什么作用?

    何為PID?為何需要PID?PID能達到什么作用? PID是英文Proportional-Integral-Derivative的縮寫,即比例-積分-微分控制器。它是一種常用的反饋控制手段,常用
    的頭像 發表于 12-07 13:37 ?1511次閱讀
    主站蜘蛛池模板: 欧美午夜性| 婷婷 夜夜| 人人干夜夜操| 免费簧片视频| 三级a黄| 色多多a| www你懂的| 天天干狠狠操| 最刺激黄a大片免费网站| 中国女人a毛片免费全部播放 | 亚洲毛片网| 国产农村妇女毛片精品久久久| 国产毛片精品| 亚洲 欧美 成人| 欧美黄三级在线观看| 大香伊人网| 国产精品夜色7777青苹果| 天堂福利视频| 18毛片| 日本免费在线| 经典三级第一页| 天天射天天爽| 狠狠色96视频| 精品国产香港三级| 在线黄网| 日本黄色影片在线观看| 国产一区二区丁香婷婷| 26uuu另类亚洲欧美日本一| 天天看天天射天天碰| 在线观看黄a| 情趣店上班h系列小说| 激情网址在线观看| 2019天天爱天天做| 日本高清午夜色wwwσ| 欧美456| 狠狠色婷婷七月色综合| 狠狠狠狼鲁欧美综合网免费| 欧美最猛性xxxx免费| 性欧美网站| 天天综合网天天做天天受| 最近国语剧情视频在线观看|