linux进程的高级管理,sched_yield()函数 高级进程管理
1、讓出處理器
Linux提供一個系統調用運行進程主動讓出執行權:sched_yield。進程運行的好好的,為什么需要這個函數呢?有一種情況是用戶空間線程的鎖定。如果一個線程試圖取得另一個線程所持有的鎖,則新的線程應該讓出處理器知道該鎖變為可用。用戶空間鎖沒有內核的支持,這是一個最間單、最有效率的做法。但是現在Linux線程實現引入一個使用futexes的優化解決方案。
另一個情況是在有處理器密集型程序可用周期性調用sched_yield,試圖將該進程對系統的沖擊減到最小。不管怎么說,如何調度程序應該是系統的事情,而不是進程自己去管。eg:
int main(){ int ret, i;
ret = sched_yield(); if(ret == -1){
printf("調用sched_yield失敗!\n");
} return 0;
}
那該調用內核是如何實現的?2.6以前的版本sched_yield所造成的影響非常小,如果存在另一個可以運行的進程,內核就切換到該進程,把進行調用的進程放在可運行進程列表的結尾處。短期內內核會對該進程進行重新調度。這樣的話可能出現“乒乓球”現象,也就是兩個程序來回運行,直到他們都運行結束。2.6版本中做了一些改變:
如果進程是RR,把它放到可運行進程結尾,返回。
否則,把它從可運行進程列表移除,放到到期進程列表,這樣在其他可運行進程時間片用完之前不會再運行該進程。
從可執行進程列表中找到另一個要執行的進程。
2、進程的優先級
看過CFS中會看到進程的nice value會決定進程會運行多長時間,或者說是占用的百分比。可以通過系統調用nice來設置、獲取進程的nice value。該值的范圍是-20~19,越低的值越高的優先級(這個在計算虛擬時間的時候放在分母上),實時進程應該是負數,eg:
int main(){ int ret, i;
ret = nice(0);
printf("當前進程的nice value:%d\n", ret);
ret = nice(10);
printf("當前進程的nice value:%d\n", ret); return 0;
}
因為ret本來就可以是-1,那么在判斷是否系統調用失敗的時候就要綜合ret和errno。還有兩個系統調用可以更靈活地設置,getpriority可以獲得進程組、用戶的任何進程中優先級最高的。setpriority將所指定的所有進程優先級設置為prio,eg:
int main(){ int ret, i;
ret = getpriority(PRIO_PROCESS, 0);
printf("nice value:%d\n", ret);
ret = setpriority(PRIO_PROCESS, 0, 10);
ret = getpriority(PRIO_PROCESS, 0);
printf("nice value:%d\n", ret); return 0;
}
進程有在處理器上執行的優先級,也有傳輸數據的優先級:I/O優先級。linux有額外的兩個系統調用可用顯示設置和取得I/O nice value,但是尚未導出:
int ioprio_get(int which, int who); int ioprio_set(int which, int who, int ioprio);
3、處理器親和性
Linux支持具有多個處理器的單一系統。在SMP上,系統要決定每個處理器上要運行那些程序,這里有兩項挑戰:
調度程序必須想辦法充分利用所有的處理器。
切換程序運行的處理器是需要代價的。
進程會繼承父進程的處理器親和性,Linux提供兩個系統調用用于獲取和設定“硬親和性”。eg:
int main(){ int ret, i;
cpu_set_t set;
CPU_ZERO(&set);
ret = sched_getaffinity(0, sizeof(cpu_set_t), &set); if(ret == -1)
printf("調用失敗!\n"); for(i = 0; i < 10; i++){ int cpu = CPU_ISSET(i, &set);
printf("cpu=%i is %s\n", i, cpu?"set":"unset");
}
CPU_ZERO(&set);
CPU_SET(0, &set);
CPU_CLR(1, &set);
ret = sched_setaffinity(0, sizeof(cpu_set_t), &set); if(ret == -1)
printf("調用失敗!\n"); for(i = 0; i < 10; i++){ int cpu = CPU_ISSET(i, &set);
printf("cpu=%i is %s\n", i, cpu?"set":"unset");
} return 0;
}
4、Linux的調度策略與優先級
關于Linux系統中對進程的幾種調度方法和他們的區別就不在這里說了,這里關注的是如何獲取、設置這些值。可以使用sched_getscheduler來獲取進程的調度策略,eg:
int main(){ int ret, i; struct sched_param sp;
sp.sched_priority = 1;
ret = sched_setscheduler(0, SCHED_RR, &sp); if(ret == -1)
printf("sched_setscheduler failed.\n"); if(errno == EPERM)
printf("Process don't the ability.\n");
ret = sched_getscheduler(0); switch(ret){ case SCHED_OTHER:
printf("Policy is normal.\n"); break; case SCHED_RR:
printf("Policy is round-robin.\n"); break; case SCHED_FIFO:
printf("Policy is first-in, first-out.\n"); break; case -1:
printf("sched_getscheduler failed.\n"); break; default:
printf("Unknow policy\n");
} return 0;
}
sched_getparam和sched_setparam接口可用于取得、設定一個已經設定好的策略,這里不只是返回一個策略的ID,eg:
int main(){ int ret, i; struct sched_param sp;
sp.sched_priority = 1;
ret = sched_setparam(0, &sp); if(ret == -1)
printf("sched_setparam error.\n");
ret = sched_getparam(0, &sp); if(ret == -1)
printf("sched_getparam error.\n");
printf("our priority is %d.\n", sp.sched_priority); return 0;
}
Linux提供兩個用于取得有效優先值的范圍的系統調用,分別返回最大值、最小值,eg:
int main(){ int ret, i; struct sched_param sp;
ret = sched_get_priority_min(SCHED_RR); if(ret == -1)
printf("sched_get_priority_min error.\n");
printf("The min nice value is %d.\n", ret);
ret = sched_get_priority_max(SCHED_RR); if(ret == -1)
printf("sched_get_priority_max error.\n");
printf("The mmax nice value is %d.\n", ret); return 0;
}
關于時間片,這個概念可能在Linux中和傳統的在操作系統的課程中學到的還是有很大的區別的,如果感興趣的化可以看看CFS里面的。通過sched_rr_get_interval可以取到分配給pid的時間片的長度,eg:
int main(){ int ret, i; struct timespec tp;
ret = sched_rr_get_interval(0, &tp); if(ret == -1)
printf("sched_rr_get_interval error.\n");
printf("The time is %ds:%ldns.\n", (int)tp.tv_sec, tp.tv_nsec); return 0;
}
5、實時進程的預防措施
由于實時進程的本質,開發者在開發和調試此類程序時應該謹慎行事,如果一個實時進程突然發脾氣,系統的反應會突然變慢。任何一個CPU密集型循環在一個實時程序中會繼續無止境地運行下去,只要沒有優先級更高實時進程變成可運行的。因此設計實時程序的時候要謹慎,這類程序至高無上,可用輕易托跨整個系統,下面是一些要決與注意事項:
因為實時進程會好用系統上一切資源,小心不要讓系統其他進程等不到處理時間。
循環可能會一直運行到結束。
小心忙碌等待,也就是實時進程等待一個優先級低的進程所占有的資源。
開發一個實時進程的時候,讓一個終端保持開啟狀態,以更高的優先級來運行該實時進程,發生緊急情況終端機依然會有反應,允許你終止失控的實時進程。
使用chrt設置、取得實時屬性。
6、資源限制
Linux對進程加上了若干資源限制,這些限制是一個進程所能耗用的內核資源的上限。限制的類型如下:
RLIMIT_AS:地址空間上限。
RLIMIT_CORE:core文件大小上限。
RLIMIT_CPU:可耗用CPU時間上限。
RLIMIT_DATA:數據段與堆的上限。
RLIMIT_FSIZE:所能創建文件的大小上限。
RLIMIT_LOCKS:文件鎖數目上限。
RLIMIT_MEMLOCK:不具備CAP_SYS_IPC能力的進程最多將多少個字節鎖進內存。
RLIMIT_MSGQUEUE:可以在消息隊列中分配多少字節。
RLIMIT_NICE:最多可以將自己的友善值調多低。
RLIMIT_NOFILE:文件描述符數目的上限。
RLIMIT_NPROC:用戶在系統上能運行進程數目上限。
RLIMIT_RSS:內存中頁面的數目的上線。
RLIMIT_RTPRIO:不具備CAP_SYS_NICE能力進程所能請求的實時優先級的上限。
RLIMIT_SIGPENDING:在隊列中信號量的上限,Linux特有的限制。
RLIMIT_STACK:堆棧大小的上限。
這些就不多說了,到了實際用到的時候再仔細看,eg:
int main(){ int ret, i; struct rlimit rlim;
rlim.rlim_cur = 32*1024*1024;
rlim.rlim_max = RLIM_INFINITY;
ret = setrlimit(RLIMIT_CORE, &rlim);
ret = getrlimit(RLIMIT_CORE, &rlim); if(ret == -1)
printf("getrlimit error.\n");
printf("RLIMIT_CORE limits: soft=%ld hard=%ld\n", rlim.rlim_cur, rlim.rlim_max); return 0;
}
總結
以上是生活随笔為你收集整理的linux进程的高级管理,sched_yield()函数 高级进程管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 历史影像再来一波(能到70年代、80年代
- 下一篇: 线上问题定位------网络瓶颈