linuxatoi
A. linux內核怎麼調度系統
1.調度器的概述
多任務操作系統分為非搶占式多任務和搶占式多任務。與大多數現代操作系統一樣,Linux採用的是搶占式多任務模式。這表示對CPU的佔用時間由操作系統決定的,具體為操作系統中的調度器。調度器決定了什麼時候停止一個進程以便讓其他進程有機會運行,同時挑選出一個其他的進程開始運行。
2.調度策略
在Linux上調度策略決定了調度器是如何選擇一個新進程的時間。調度策略與進程的類型有關,內核現有的調度策略如下:
#define SCHED_NORMAL 0#define SCHED_FIFO 1#define SCHED_RR 2#define SCHED_BATCH 3/* SCHED_ISO: reserved but not implemented yet */#define SCHED_IDLE 5
0: 默認的調度策略,針對的是普通進程。
1:針對實時進程的先進先出調度。適合對時間性要求比較高但每次運行時間比較短的進程。
2:針對的是實時進程的時間片輪轉調度。適合每次運行時間比較長得進程。
3:針對批處理進程的調度,適合那些非交互性且對cpu使用密集的進程。
SCHED_ISO:是內核的一個預留欄位,目前還沒有使用
5:適用於優先順序較低的後台進程。
註:每個進程的調度策略保存在進程描述符task_struct中的policy欄位
3.調度器中的機制
內核引入調度類(struct sched_class)說明了調度器應該具有哪些功能。內核中每種調度策略都有該調度類的一個實例。(比如:基於公平調度類為:fair_sched_class,基於實時進程的調度類實例為:rt_sched_class),該實例也是針對每種調度策略的具體實現。調度類封裝了不同調度策略的具體實現,屏蔽了各種調度策略的細節實現。
調度器核心函數schele()只需要調用調度類中的介面,完成進程的調度,完全不需要考慮調度策略的具體實現。調度類連接了調度函數和具體的調度策略。
武特師兄關於sche_class和sche_entity的解釋,一語中的。
調度類就是代表的各種調度策略,調度實體就是調度單位,這個實體通常是一個進程,但是自從引入了cgroup後,這個調度實體可能就不是一個進程了,而是一個組
- static inline struct task_struct *pick_next_task(struct rq *rq){ const struct sched_class *class; struct task_struct *p; /*
- * Optimization: we know that if all tasks are in
- * the fair class we can call that function directly:
- *///基於公平調度的普通進程
- if (likely(rq->nr_running == rq->cfs.nr_running)) {
- p = fair_sched_class.pick_next_task(rq); if (likely(p)) return p;
- }//基於實時調度的實時進程
- class = sched_class_highest; for ( ; ; ) {
- p = class->pick_next_task(rq); //實時進程的類
- if (p) return p; /*
- * Will never be NULL as the idle class always
- * returns a non-NULL p:
- */
- class = class->next; //rt->next = fair; fair->next = idle
- }
- }
- struct rt_prio_array {
- DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */
- struct list_head queue[MAX_RT_PRIO];
- };
- define DECLARE_BITMAP(name,bits)
- unsigned long name[BITS_TO_LONGS(bits)]
- #include <sched.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#define DEATH(mess) { perror(mess); exit(errno); }void printpolicy (int policy){ /* SCHED_NORMAL = SCHED_OTHER in user-space */
- if (policy == SCHED_OTHER) printf ("policy = SCHED_OTHER = %d ", policy); if (policy == SCHED_FIFO) printf ("policy = SCHED_FIFO = %d ", policy); if (policy == SCHED_RR) printf ("policy = SCHED_RR = %d ", policy);
- }int main (int argc, char **argv){ int policy; struct sched_param p; /* obtain current scheling policy for this process */
- //獲取進程調度的策略
- policy = sched_getscheler (0);
- printpolicy (policy); /* reset scheling policy */
- printf (" Trying sched_setscheler... ");
- policy = SCHED_FIFO;
- printpolicy (policy);
- p.sched_priority = 50; //設置優先順序為50
- if (sched_setscheler (0, policy, &p))
- DEATH ("sched_setscheler:"); printf ("p.sched_priority = %d ", p.sched_priority); exit (0);
- }
- [root@wang schele]# ./get_schele_policy policy = SCHED_OTHER = 0
- Trying sched_setscheler...
- policy = SCHED_FIFO = 1
- p.sched_priority = 50
4.schele()函數
linux 支持兩種類型的進程調度,實時進程和普通進程。實時進程採用SCHED_FIFO 和SCHED_RR調度策略,普通進程採用SCHED_NORMAL策略。
preempt_disable():禁止內核搶占
cpu_rq():獲取當前cpu對應的就緒隊列。
prev = rq->curr;獲取當前進程的描述符prev
switch_count = &prev->nivcsw;獲取當前進程的切換次數。
update_rq_clock() :更新就緒隊列上的時鍾
clear_tsk_need_resched()清楚當前進程prev的重新調度標志。
deactive_task():將當前進程從就緒隊列中刪除。
put_prev_task() :將當前進程重新放入就緒隊列
pick_next_task():在就緒隊列中挑選下一個將被執行的進程。
context_switch():進行prev和next兩個進程的切換。具體的切換代碼與體系架構有關,在switch_to()中通過一段匯編代碼實現。
post_schele():進行進程切換後的後期處理工作。
5.pick_next_task函數
選擇下一個將要被執行的進程無疑是一個很重要的過程,我們來看一下內核中代碼的實現
對以下這段代碼說明:
1.當rq中的運行隊列的個數(nr_running)和cfs中的nr_runing相等的時候,表示現在所有的都是普通進程,這時候就會調用cfs演算法中的pick_next_task(其實是pick_next_task_fair函數),當不相等的時候,則調用sched_class_highest(這是一個宏,指向的是實時進程),這下面的這個for(;;)循環中,首先是會在實時進程中選取要調度的程序(p = class->pick_next_task(rq);)。如果沒有選取到,會執行class=class->next;在class這個鏈表中有三種類型(fair,idle,rt).也就是說會調用到下一個調度類。
在這段代碼中體現了Linux所支持的兩種類型的進程,實時進程和普通進程。回顧下:實時進程可以採用SCHED_FIFO 和SCHED_RR調度策略,普通進程採用SCHED_NORMAL調度策略。
在這里首先說明一個結構體struct rq,這個結構體是調度器管理可運行狀態進程的最主要的數據結構。每個cpu上都有一個可運行的就緒隊列。剛才在pick_next_task函數中看到了在選擇下一個將要被執行的進程時實際上用的是struct rq上的普通進程的調度或者實時進程的調度,那麼具體是如何調度的呢?在實時調度中,為了實現O(1)的調度演算法,內核為每個優先順序維護一個運行隊列和一個DECLARE_BITMAP,內核根據DECLARE_BITMAP的bit數值找出非空的最高級優先隊列的編號,從而可以從非空的最高級優先隊列中取出進程進行運行。
我們來看下內核的實現
數組queue[i]裡面存放的是優先順序為i的進程隊列的鏈表頭。在結構體rt_prio_array 中有一個重要的數據構DECLARE_BITMAP,它在內核中的第一如下:
5.1對於實時進程的O(1)演算法
這個數據是用來作為進程隊列queue[MAX_PRIO]的索引點陣圖。bitmap中的每一位與queue[i]對應,當queue[i]的進程隊列不為空時,Bitmap的相應位就為1,否則為0,這樣就只需要通過匯編指令從進程優先順序由高到低的方向找到第一個為1的位置,則這個位置就是就緒隊列中最高的優先順序(函數sched_find_first_bit()就是用來實現該目的的)。那麼queue[index]->next就是要找的候選進程。
如果還是不懂,那就來看兩個圖
由結果可以看出當nice的值越小的時候,其睡眠時間越短,則表示其優先順序升高了。
7.關於獲取和設置優先順序的系統調用:sched_getscheler()和sched_setscheler
輸出結果:
可以看出進程的優先順序已經被改變。
B. linux下有沒有對一列數字進行求和的命令
額,目測沒有這樣的程序。
不過可以自己寫一個c的實現
#include<stdio.h>
#include<stdlib.h>
intmain(intargc,char*argv[])
{
inti,res=0;
for(i=1;i<argc;i++)
res+=atoi(argv[i]);
printf("%d",res);
return0;
}
匆忙寫的,可能有問題,見諒。
編譯後用 ./a.out 1 2 3 4 5...... numberN調用即可。
C. Linux下的c編程:系統調用
標準的c函數庫是所有的編譯都要具有的函數庫,(實際上還是略有不同),但是這些基本上實現方法略有不同,但是結果和標準是一樣的。但是linux的系統調用,調用是linux的系統庫,比如說unistd.h下的fork這個是Linux下特有,你在vs上,就沒有這個庫,也沒有這個函數。同樣在vs上寫c,你可以引入頭文件比如windows.h,顯然這個庫是Linux不具有的。簡單說系統調用庫根據具體的操作系統環境不同而不同,而c標准庫,是所有支持c語言編譯器都有的。
D. 如何查詢Linux內核函數
如果要看這兩個函數在標准庫中的定義用ctags或cscope生成索引.h,cscope,可以跳轉到函數定義,man malloc,聲明見stdlib。
如果仍然找不到,可以用ctags,si或grep。
windows下用source insight也可,然後查找函數定義,用grep -r 搜索關鍵字,atoi和malloc在C的標准庫中有定義。
1.安裝ctags
在源代碼目錄下運行
ctags -R
這樣,會遞歸生成當前目錄下及其子目錄的tags文件。
2.使用VIM根據tags文件查找函數或結構定義。
1.在源碼目錄下查找
vi -t tagname
2.如果要在任意位置使用,則需要把該tags文件添加到~/.vimrc文件中
set tags=/home/money/sda8/2.6232/tags
3.如果要在代碼中實時跟蹤,則游標移動到函數名上,使用CTRL+]鍵,按CTRL+t可以返回。
如果要跟蹤系統函數,使用shift+K可以自動跳轉道游標所在函數的手冊。