㈠ 淺析linux下進程的調度策略與優先順序
在 Linux 中,線程是由進程來實現的,可以認為線程就是一個輕量級的進程,因此,線程調度是按照進程調度的方式來進行的。這樣設計,線程調度流程可以直接復用進程調度流程,沒必要再設計一個進程內的線程調度器了。
在 Linux 中,進程調度器是基於進程的調度策略與調度優先順序來決定調度哪個進程運行。
調度策略主要包括:
調度優先順序的范圍是 0~99,數值越大,表示優先順序越高。
其中,SCHED_OTHER、SCHED_IDLE、SCHED_BACH 為非實時調度策略,其調度優先順序為 0。而 SCHED_FIFO、SCHED_RR 是實時調度策略,其調度優先順序范圍為 1~99。
實時調度策略的進程總是比非實時調度策略的進程優先順序高。
在 Linux 內部實現中,調度器會為每個可能的調度優先順序維護一個可運行的進程列表,以最高優先順序列表頭部的進程作為下一次調度的進程,所有的調度都是搶占式的,如果一個具有更高調度優先順序的進程轉換為可運行狀態,那麼當前運行的進程將被強制進入其等待的隊列中。
SCHED_OTHER
該調度策略是默認的 Linux 分時調度策略,該調度策略為非實時的,其調度優先順序總是為 0。
對於該調度策略類型的進程,調度器是基於動態優先順序來調度的。動態優先順序跟屬性 nice 有關,nice 的值會隨著進程的運行時間而動態改變,以確保所有具有 SCHED_OTHER 策略的進程公平地得到調度。
在 Linux 中,nice 的值范圍為-20 ~ +19,默認值為 0。nice 值越大,則優先順序越低,因此相對較低 nice 值的進程可以獲得更多的處理器時間。
通過命令 ps -el 查看系統中的進程列表,其中 NI 列就是進程對應的 nice 值。
使用 top 命令,看到的 NI 列也是進程的 nice 值。
調整 nice 值,可以通過 shell 命令 nice ,該命令可以按照指定的 nice 值運行 cmd ,命令的幫助信息為:
重新調整已運行進程的 nice 值,可通過 renice 命令實現,命令的幫助信息為:
另外,可以執行 top 命令,輸入 r ,根據提示輸入進程的 pid ,再輸入 nice 數值,也可以調整進程的 nice 值。
SCHED_FIFO
該調度策略為先入先出調度策略,簡單概括,就是一旦進程佔用了 CPU,則一直運行,直到有更高優先順序的任務搶占,或者進程自己放棄佔用 CPU。
SCHED_RR
該調度策略為時間片輪轉調度策略,該調度策略是基於 SCHED_FIFO 策略的演進,其在每個進程上增加一個時間片限制,當時間片使用完成後,調度器將該進程置於隊列的尾端,放在尾端保證了所有具有相同調度優先順序的進程的調度公平。
使用 top 命令,如果 PR 列的值為 RT ,則說明該進程採用的是實時調度策略,其調度策略為 SCHED_FIFO 或者 SCHED_RR,而對於非實時調度策略的進程,該列的值為 NI + 20 。
可以通過命令 ps -eo state,uid,pid,ppid,rtprio,time,comm 來查看進程對應的實時優先順序,實時優先順序位於 RTPRIO 列下,如果進程對應的列顯示為 - ,說明該進程不是實時進程。
chrt 命令可以用來很簡單地更改進程的調度策略與調度優先順序。在 Linux 下查看 chrt 命令的幫助信息:
比如,獲取某個進程的調度策略,使用如下命令:
在比如,設置某個進程的調度策略為 SCHED_FIFO,調度優先順序為 70,使用如下命令:
㈡ linux進程、線程及調度演算法(三)
調度策略值得是大家都在ready時,並且CPU已經被調度時,決定誰來運行,誰來被調度。
兩者之間有一定矛盾。
響應的優化,意味著高優先順序會搶占優先順序,會花時間在上下文切換,會影響吞吐。
上下文切換的時間是很短的,幾微妙就能搞定。上下文切換本身對吞吐並多大影響, 重要的是,切換後引起的cpu 的 cache miss.
每次切換APP, 數據都要重新load一次。
Linux 會盡可能的在響應與吞吐之間尋找平衡。比如在編譯linux的時候,會讓你選擇 kernal features -> Preemption model.
搶占模型會影響linux的調度演算法。
所以 ARM 的架構都是big+LITTLE, 一個很猛CPU+ 多個 性能較差的 CPU, 那麼可以把I/O型任務的調度 放在 LITTLE CPU上。需要計算的放在big上。
早期2.6 內核將優先順序劃分了 0-139 bit的優先順序。數值越低,優先順序越高。0-99優先順序 都是 RT(即時響應)的 ,100-139都是非RT的,即normal。
調度的時候 看哪個bitmap 中的 優先順序上有任務ready。可能多個任務哦。
在普通優先順序線程調度中,高優先順序並不代表對低優先順序的絕對優勢。會在不同優先順序進行輪轉。
100 就是比101高,101也會比102高,但100 不會堵著101。
眾屌絲進程在輪轉時,優先順序高的:
初始設置nice值為0,linux 會探測 你是喜歡睡眠,還是幹活。越喜歡睡,linux 越獎勵你,優先順序上升(nice值減少)。越喜歡幹活,優先順序下降(nice值增加)。所以一個進程在linux中,干著干著 優先順序越低,睡著睡著 優先順序越高。
後期linux補丁中
紅黑樹,數據結構, 左邊節點小於右邊節點
同時兼顧了 CPU/IO 和 nice。
數值代表著 進程運行到目前為止的virtual runtime 時間。
(pyhsical runtime) / weight * 1024(系數)。
優先調度 節點值(vruntime)最小的線程。權重weight 其實有nice 來控制。
一個線程一旦被調度到,則物理運行時間增加,vruntime增加,往左邊走。
weight的增加,也導致vruntime減小,往右邊走。
總之 CFS讓線程 從左滾到右,從右滾到左。即照顧了I/O(喜歡睡,分子小) 也 照顧了 nice值低(分母高).所以 由喜歡睡,nice值又低的線程,最容易被調度到。
自動調整,無需向nice一樣做出獎勵懲罰動作,個人理解權重其實相當於nice
但是 此時 來一個 0-99的線程,進行RT調度,都可以瞬間秒殺你!因為人家不是普通的,是RT的!
一個多線程的進程中,每個線程的調度的策略 如 fifo rr normal, 都可以不同。每一個的優先順序都可以不一樣。
實驗舉例, 創建2個線程,同時開2個:
運行2次,創建兩個進程
sudo renice -n -5(nice -5級別) -g(global), 會明顯看到 一個進程的CPU佔用率是另一個的 3倍。
為什麼cpu都已經達到200%,為什麼系統不覺得卡呢?因為,我們的線程在未設置優先順序時,是normal調度模式,且是 CPU消耗型 調度級別其實不高。
利用chrt工具,可以將進程 調整為 50 從normal的調度策略 升為RT (fifo)級別的調度策略,會出現:
chrt , nice renice 的調度策略 都是以線程為單位的,以上 設置的將進程下的所有線程進行設置nice值
線程是調度單位,進程不是,進程是資源封裝單位!
兩個同樣死循環的normal優先順序線程,其中一個nice值降低,該線程的CPU 利用率就會比另一個CPU的利用率高。
㈢ 如何進行Linux下多線程的調試
方法一:PS
在ps命令中,「-T」選項可以開啟線程查看。下面的命令列出了由進程號為<pid>的進程創建的所有線程。
1.$ ps -T -p <pid>
「SID」欄表示線程ID,而「CMD」欄則顯示了線程名稱。
方法二: Top
top命令可以實時顯示各個線程情況。要在top輸出中開啟線程查看,請調用top命令的「-H」選項,該選項會列出所有Linux線程。在top運行時,你也可以通過按「H」鍵將線程查看模式切換為開或關。
1.$ top -H
要讓top輸出某個特定進程<pid>並檢查該進程內運行的線程狀況:
$ top -H -p <pid>
㈣ 淺談linux 多線程編程和 windows 多線程編程的異同
linux下線程的實現,linux的線程編程有兩個庫pthread和pth,對於pthread的實現是內核方式的實現,每個線程在kernel中都有task結構與之對應,也就是說用ps命令行是可以看見多個線程,線程的調度也是由內核中的schele進行的。
再來看看Windows的多線程,Windows NT和Windows95是一個搶先型多任務、多線程操作系統。因為它使用搶先型的多任務,所以它擁有與UNIX同樣平滑的處理和進程獨立。多線程就更進一步。一個獨立的程序默認是使用一個線程,不過它可以將自己分解為幾個獨立的線程來執行,例如,其中的一個線程可以發送一個文件到列印機,而另一個可以響應用戶的輸入。這個簡單的程序設計修改可以明顯減少用戶等待的時間,讓用戶無需擔心長時間的計算、重繪屏幕、文件讀寫等帶來的不便。
多線程還可以讓你從許多高端的多處理器NT機器中得到好處。例如,你購買了一個高級的RISC機器,可以使用多達10個CPU晶元,但在開始的時候你只購買了一個CPU。你寫了一個簡單的Mandelbrot set程序,你發現需要15秒的時間來重新繪制Mandelbrot set的畫面。
那麼,Windows平台的線程和類Unix平台(包括Linux)的進程的區別是什麼呢?
熟悉WIN32編程的人一定知道,WIN32的進程管理方式與UNIX上有著很大區別,在UNIX里,只有進程的概念,但在WIN32里卻還有一個「線程」的概念,那麼UNIX和WIN32在這里究竟有著什麼區別呢?
UNIX里的fork是七十年代UNIX早期的開發者經過長期在理論和實踐上的艱苦探索後取得的成果,一方面,它使操作系統在進程管理上付出了最小的代價,另一方面,又為程序員提供了一個簡潔明了的多進程方法。
WIN32里的進程/線程是繼承自OS/2的。在WIN32里,「進程」是指一個程序,而「線程」是一個「進程」里的一個執行「線索」。從核心上講,WIN32的多進程與UNIX並無多大的區別,在WIN32里的線程才相當於UNIX的進程,是一個實際正在執行的代碼。但是,WIN32里同一個進程里各個線程之間是共享數據段的。這才是與UNIX的進程最大的不同。
對於多任務系統,共享數據區是必要的,但也是一個容易引起混亂的問題,在WIN32下,一個程序員很容易忘記線程之間的數據是共享的這一情況,一個線程修改過一個變數後,另一個線程卻又修改了它,結果引起程序出問題。但在UNIX下,由於變數本來並不共享,而由程序員來顯式地指定要共享的數據,使程序變得更清晰與安全。
㈤ linux如何實現多線程
#/bin/bashall_num=10a=$(date +%H%M%S)for num in `seq 1 ${all_num}`do
sleep 1
echo ${num}
done
b=$(date +%H%M%S)
echo -e "startTime:\t$a"echo -e "endTime:\t$b"
㈥ linux多線程程序怎麼調試
多線程程序可能存在很多潛在的bug,如data race,dead lock,信號bug等,而這些bug一向很難調試,現在有很多論文都是基於多線程程序的調試技術的,比如model check,死鎖檢測,replay技術等,也有很多對應的工具,如intel的pinplay,微軟的Zing等。關於這些技術和工具,如果感興趣可以 google相應的論文進一步了解。這里我主要講述的是我在對二進制翻譯下多線程程序調試中經常使用的一些方法以及一些調試經驗,雖然我的調試的是二進制翻譯器,但是這些方法也同樣適用於大多數多線程程序。
1、最直接的方法就是在源程序插入printf語句來列印出一些有用的變數。這種方法的優點是不用藉助其他工具就可以對程序的運行進行觀察,缺點是插入語句的位置、粒度等都需要調試者自己去權衡,如果插入過多的列印語句,則頻繁的IO操作會使程序運行變慢,線程行為改變,有些bug甚至不會再出現。至於需要在什麼地方插入語句,首先,只列印有必要的變數,一個語句可以列印多個變數;其次,在循環中,我們可以通過設置一些條件來降低列印的粒度,比如下面這段代碼:
1 2 3 4 5 6 7 8 while(flag){ pc = getpc(); printf(「pc is:0x%x\n」, pc);//我們插入的列印語句 ...... ...... //do somthing using pc; }
假設我們對pc的取值很感興趣,需要列印出所有pc取到過的值,但是大多數情況下,getpc()的返回值都同上一次的返回值相同,這樣我們printf出來的就會有很多重復值。這種情況下我們可以用下面這種插樁方式來去處重復值:
1 2 3 4 5 6 7 8 9 10 11 int lastpc; //定義為全局變數或局部靜態變數 while(flag){ pc = getpc(); if(pc !=lastpc){ lastpc = pc; printf(「pc is:0x%x\n」, pc); } ...... ......//do somthing using pc }
這樣通過一個簡單的判斷就可以省掉很多沒有必要的輸出。很多別的情形,比如我們只關心某一變數等於特定值(比如0)時其他變數的狀態,我們就沒有必要把改變數不等於0時的狀態列印出來。總之,能省則省,只列印我們需要的。
2、利用gdb的attach功能和sleep()函數。gdb是由gnu維護的功能強大的調試工具,並且支持多線程程序的調試,可以在gdb下直接運行一個多線程程序,通過thread等命令進行調試。但是很多多線程程序在其他工具(gdb,pin,strace等)監管下,原有的bug就不會出現。這的確是很讓人頭疼的事情,也是我十分不喜歡這個方法的原因,想像一下,一個程序直接跑就出錯,但是放到gdb下就能得到正確的結果,好像故意在耍我們一樣。我更喜歡使用gdb的attach功能,我們可以通過下面的命令來讓gdb接管一個運行的線程:
1 gdb attach <pid>
這種方法的好處是能夠使gdb對程序執行的影響最小,而且可以只接管程序中某一條我們所關心的線程,而其他線程不受影響。
這時有人會問,如果線程執行過快,我們還沒來得及attach線程就已經執行完或者mp掉了,這種情況該怎麼辦?解決方法很簡單,既然線程執行過快,我們就讓它等一等,可以在源代碼中讓我們關心這個線程sleep()一小會兒,這樣我們就有足夠的時間來attach它,並且attach的位置我們也可以進行控制,想在哪裡attach,就在哪裡sleep。
3、第三種方法是利用信號處理函數來獲取一些信息。在多線程程序的壓力測試中,很多錯誤要每隔幾百幾千次運行才能出現一次,而這種錯誤的replay是很困難的,因此捕捉到這種錯誤的現場很重要。這里我習慣利用信號處理程序來保存這樣的現場,這樣你可以晚上寫個腳本讓程序無限跑,早上起來你會發現程序停在出錯的地方,這是很愜意的事情。
多數多線程程序出錯,都是訪問非法內存,也就是我們常說的「段錯誤」(segmentation fault),程序發生非法內存的訪問,系統會發給線程一個SIGSEGV信號,這個信號默認處理為core掉該線程。我們可以對這個信號進行利用,為其注冊一個信號處理函數:
1 2 3 4 struct sigaction act; act.sa_flags = SA_SIGINFO; act.sa_sigaction = signal_handler; sigaction(SIGSEGV, &act, NULL); //SIGSEGV表示該信號的值
信號處理函數如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void signal_handler(int host_signum, siginfo_t *info, void *puc){ structucontext *uc = (struct ucontext *)puc; int loopflag = 1; while(loopflag)//可以在gdb中手動更改loopflag的值跳出循環 sleep(1); ...... //這里可以列印一些感興趣的變數 }
函數參數中,puc是一個體系結構相關的指針,不同的體系結構,指針指向的結構不一樣,裡面存放了發生信號時線程的寄存器的值,程序地址等信息,函數內第一句話的目的就是把void類型轉換成ucontext結構類型,這樣在gdb中可以直接print出該結構的成員。
函數中sleep的作用是讓程序停在信號處理程序中,以給我們足夠的時間進行attach。如果想讓程序繼續運行下去,手動把loopflag修改為1即可。用while循環的目的是我們可以在運行時手動控制sleep的時間。
這種方法同樣適用於其他信號帶來的bug,比如SIGBUS等。在二進制翻譯下,還可以使用這種方法對二進制翻譯器信號處理進行跟蹤和調試,具體使用讀者可以自己去發掘。
4、利用strace得到我們關心的信息。大多數情況下我們用strace的目的是跟蹤系統調用,但其實strace對多線程程序的調試有很大的幫助,使用strace列印多線程程序信息的命令如下:
1 strace -F ./test
如果我們對某些系統調用,如gettimeofday,ioctl不感興趣,可以屏蔽掉
1 strace -F -etrace=\!gettimeofday,ioctl ./test
通過strace列印出的信息,我們可以對什麼時候產生了一個子線程,那個線程在等待,哪個線程被喚醒,哪個線程收到信號,哪個線程core掉有一個綜合的了解,這些信息對多線程調試會起到很大的作用。
還有很多方法比如利用core文件等,很多地方可以查到,我不做累贅的介紹。總之技術是死的,但是方法是靈活的,當傳統方法解決不了一個問題的時候,可以放開思路嘗試其他的方法。
㈦ Linux系統進程調度
主要參考 :Linux manual page - sched
自從linux內核2.6.23以來,默認的進高嘩扮程調度器就被設置為完全公平調度器(CFS,complete fair scheler),取代了之前的O(1)調度器。
每個線程都有一個靜態調度優先順序,即 sched_priority 欄位。
一個線程的調度策略決定了線程會被插入到同級靜態優先順序的線程隊列的位置,以及它在隊列中會怎樣移動。
所有的調度都是可插入的,如果一個更高靜態優先順序的線程准備好了,現在運行中的線程就會被插入。而調度策略則僅僅影響了同樣靜態優先順序的線程。
進程(線程)可以通過系蘆橋統調用設置自身或者其他進程(線程)的調度策略。
其中 pid 為0時,設置自身的調度策略和參數。結構體 sched_attr 包含以下戚灶欄位: size 、 sched_policy (即調度策略,具體會在下一節介紹)、 sched_flags 、 sched_nice 、 sched_runtime 、 sched_deadline 、 sched_period (最後三個為 SCHED_DEADLINE 相關的參數)。當設置成功,系統調用返回0;否則返回-1,並會設置 errno 。
普通進程: SCHED_OTHER / SCHED_BATCH / SCHED_IDLE
實時進程: SCHED_FIFO / SCHED_RR
特殊實時進程: SCHED_DEADLINE
靜態優先順序:Static_priority:對於普通進程,靜態優先順序為0;對於實時進程,靜態優先順序為1-99,99為最高優先順序。
動態優先順序:Dynamic_priority:僅對普通進程有用,取決於nice和一個動態調整的量(比如進程ready卻沒被調度,則增加)。
㈧ 現在的多核CPU,Linux操作系統是否能夠實現單個進程(多線程)的多核調度(跨CPU核心調度)
現在的技術,還是一個線程只能運行在一個 CPU 上。多核心,必須用多線程/進程來運行才能實現最大化。當然,你可以單個線程不停的在所有的 CPU 上來回跳。但是效率會很低很低。
因為 CPU 有寄存器和緩存的問題。如果你切換 CPU 運行,所有的數據都要進行一次傳遞。非常浪費時鍾(在 CPU 上,程序執行不是一個時鍾馬上就能任意執行一個指令,而是流水線作業,一個指令需要很多個時鍾才能處理完,數據存取也都要等)。
這也因為程序原本就都是順序執行的。你沒辦法讓一個程序的後面的結果可以跳過前面的結果而得出。
當然,現在 CPU 確實有這種技術,叫做亂序執行。也就是當前面的過程還沒有計算時,後面的指令先計算。但是這種事情是要靠猜測的,而且這也僅僅是分支預測,依然不能預測某個計算的結果。即便猜的再准確,也有錯的時候。奔騰4 最老的版本就有這個問題,流水線太長。計算後發現錯了。整條流水線需要清空重新計算。有嚴重性能問題的奔騰4 CPU ,流水線長度是 31 級。也就是一個程序至少 31 個時鍾周期才能從推到流水線後到真正執行。直接浪費了 31 個時鍾周期。
所以目前的技術來說,單線程多核新協同計算,技術上不可能實現。
提高性能,就是整理數據處理的演算法,把多次重復計算的過程,拆成多條線程分別計算。從而保證 CPU 多核新的效率最大化。每個線程可以共享同一塊數據,自己讀取自己的數據計算使可以的。不過,這時候就有另外一個問題,數據定址和傳遞的性能問題。
㈨ linux多線程
線程是進程內獨立的一條運行路線,處理器調度的最小單元,也可以稱為輕量級進程。線程可以對進程的內存空間和資源進行訪問,並與同一進程中的其他線搏好程共享。因此,線程的上下文切換的開銷比創建圓銀拆進程小很多。
Pthread是一套用戶級線程庫,但在linux上實現時,卻使用了內核級線程來完成,這樣提高的線程的並發性.Pthread是由POSIX提供的橘棗一套通用的線程庫,具有很好的移植性.
㈩ Linux下多線程和多進程程序的優缺點,各個適合什麼樣的業務場景
IBM有個傢伙做了個測試,發現切換線程context的時候,windows比linux快一倍多。進出最快的鎖(windows2k的 critical section和linux的pthread_mutex),windows比linux的要快五倍左右。當然這並不是說linux不好,而且在經過實際編程之後,綜合來看我覺得linux更適合做high performance server,不過在多線程這個具體的領域內,linux還是稍遜windows一點。這應該是情有可原的,畢竟unix家族都是從多進程過來的,而 windows從頭就是多線程的。
如果是UNIX/linux環境,採用多線程沒必要。
多線程比多進程性能高?誤導!
應該說,多線程比多進程成本低,但性能更低。
在UNIX環境,多進程調度開銷比多線程調度開銷,沒有顯著區別,就是說,UNIX進程調度效率是很高的。內存消耗方空數嫌面,二者只差全局數據區,現在內存都很便宜,伺服器內存動輒若干G,根本不是問題。
多進程是立體交通系統,雖然造價高,上坡下坡多耗點油,但是不堵車。
多線程是平面交通系統,造價低,但紅綠燈太多,老堵車。
我們現在都開跑車,油(主頻)有的是,不怕上坡下坡,就怕堵車。
高性能交易伺服器中間件,如TUXEDO,都是主張多進程的。實際測試表明,TUXEDO性能和並發效率是非常高的。TUXEDO是貝爾實驗室的,與UNIX同宗,應該是對UNIX理解最為深刻的,他們的意見應該具有很大的參考意義。
多線程的優點:
無需跨進程邊界;
程序邏輯和控制方式簡單;
所有線程可以直接共享內存和變數等;
線程方式消耗的總資源比進程方式好;
多線程缺點:
每個線程與主程序共用地址空間,受限於2GB地址空間;
線程之間的同步和加鎖控制比較麻煩;
一個線程的崩潰可能影響到整個程序的穩定性;
到達一定的線程數程度後,即使再增加CPU也無法提高性能,例如Windows Server 2003,大約是1500個左右的線程數就快到極限了(線程堆棧設定為1M),如果設定線程堆棧為2M,還達不到1500個線程總數;
線程能夠提高的總性能有限,而且線程多了之後,線程本身的調度也是一個麻煩事兒,需要消耗較多的畢圓CPU
多進程優點:
每個進程互相獨立,不影響主程序的穩定性,子進程崩潰沒關系;
通過增加CPU,就可以容易擴充性能;
可以盡量減少線程加鎖/解鎖的影響,極大提高性能,就算是線程運行的模塊演算法效斗手率低也沒關系;
每個子進程都有2GB地址空間和相關資源,總體能夠達到的性能上限非常大
多線程缺點:
邏輯控制復雜,需要和主程序交互;
需要跨進程邊界,如果有大數據量傳送,就不太好,適合小數據量傳送、密集運算
多進程調度開銷比較大;
最好是多進程和多線程結合,即根據實際的需要,每個CPU開啟一個子進程,這個子進程開啟多線程可以為若干同類型的數據進行處理。當然你也可以利用多線程+多CPU+輪詢方式來解決問題……
方法和手段是多樣的,關鍵是自己看起來實現方便有能夠滿足要求,代價也合適。