日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

浅析Linux线程调度

發(fā)布時(shí)間:2025/6/15 linux 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅析Linux线程调度 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?在Linux中,線程是由進(jìn)程來實(shí)現(xiàn),線程就是輕量級進(jìn)程(?lightweight?process?),因此在Linux中,線程的調(diào)度是按照進(jìn)程的調(diào)度方式來進(jìn)行調(diào)度的,也就是說線程是調(diào)度單元。Linux這樣實(shí)現(xiàn)的線程的好處的之一是:線程調(diào)度直接使用進(jìn)程調(diào)度就可以了,沒必要再搞一個(gè)進(jìn)程內(nèi)的線程調(diào)度器。在Linux中,調(diào)度器是基于線程的調(diào)度策略(scheduling?policy)和靜態(tài)調(diào)度優(yōu)先級(static?scheduling?priority)來決定那個(gè)線程來運(yùn)行。

? ? 對于下面三種調(diào)度策略SCHED_OTHER,?SCHED_IDLE,?SCHED_BATCH,其調(diào)度優(yōu)先級sched_priority是不起作用的,即可以看成其調(diào)度優(yōu)先級為0;調(diào)度策略SCHED_FIFOSCHED_RR是實(shí)時(shí)策略,他們的調(diào)度值范圍是199,數(shù)值越大優(yōu)先級越高,另外實(shí)時(shí)調(diào)度策略的線程總是比前面三種通常的調(diào)度策略優(yōu)先級更高。通常,調(diào)度器會(huì)為每個(gè)可能的調(diào)度優(yōu)先級(sched_priority?value)維護(hù)一個(gè)可運(yùn)行的線程列表,并且是以最高靜態(tài)優(yōu)先級列表頭部的線程作為下次調(diào)度的線程。所有的調(diào)度都是搶占式的:如果一個(gè)具有更高靜態(tài)優(yōu)先級的線程轉(zhuǎn)換為可以運(yùn)行了,那么當(dāng)前運(yùn)行的線程會(huì)被強(qiáng)制進(jìn)入其等待的隊(duì)列中。下面介紹幾種常見的調(diào)度策略:

? ??SCHED_OTHER:該策略是是默認(rèn)的Linux分時(shí)調(diào)度(time-sharing?scheduling)策略,它是Linux線程默認(rèn)的調(diào)度策略。SCHED_OTHER策略的靜態(tài)優(yōu)先級總是為0,對于該策略列表上的線程,調(diào)度器是基于動(dòng)態(tài)優(yōu)先級(dynamic?priority)來調(diào)度的,動(dòng)態(tài)優(yōu)先級是跟nice中相關(guān)(nice值可以由接口nice,?setpriority,sched_setattr來設(shè)置),該值會(huì)隨著線程的運(yùn)行時(shí)間而動(dòng)態(tài)改變,以確保所有具有SCHED_OTHER策略的線程公平運(yùn)行。在Linux上,nice值的范圍是-20+19,默認(rèn)值為0nice值越大則優(yōu)先級越低,相比高nice值(低優(yōu)先級)的進(jìn)程,低nice值(高優(yōu)先級)的進(jìn)程可以獲得更多的處理器時(shí)間。使用命令ps?-el查看系統(tǒng)的進(jìn)程列表,其中NI列就是進(jìn)程對應(yīng)的nice值;使用top命令,看到的NI列也是nice值。運(yùn)行命令的時(shí)候可用nice?–n?xx?cmd來調(diào)整cmd任務(wù)的nice值,xx的范圍是-20~19之間。

? ??SCHED_FIFO:先入先出調(diào)度策略(First?in-first?out?scheduling)。該策略簡單的說就是一旦線程占用cpu則一直運(yùn)行,一直運(yùn)行直到有更高優(yōu)先級任務(wù)到達(dá)或自己放棄。

? ??SCHED_RR:時(shí)間片輪轉(zhuǎn)調(diào)度(Round-robin?scheduling)。該策略是SCHED_FIFO基礎(chǔ)上改進(jìn)來的,他給每個(gè)線程增加了一個(gè)時(shí)間片限制,當(dāng)時(shí)間片用完后,系統(tǒng)將把該線程置于隊(duì)列末尾。放在隊(duì)列尾保證了所有具有相同優(yōu)先級的RR任務(wù)的調(diào)度公平。使用top命令,如果PR列的值為RT,則說明該進(jìn)程采用的是實(shí)時(shí)策略,即調(diào)度策略是SCHED_FIFO或者為SCHED_RR,而對于非實(shí)時(shí)調(diào)度策略(比如SCHED_OTHER)的進(jìn)程,該列的值是NI+20,以供Linux內(nèi)核使用。我們可以通過命令:

?

[cpp] view plain copy
  • ps?-eo?state,uid,pid,ppid,rtprio,time,comm??
  • 來查看進(jìn)程對應(yīng)的實(shí)時(shí)優(yōu)先級(位于RTPRIO列下),如果有進(jìn)程對應(yīng)的列顯示“-”,則說明它不是實(shí)時(shí)進(jìn)程。注意任何實(shí)時(shí)策略進(jìn)程的優(yōu)先級都高于普通的進(jìn)程,也就說實(shí)時(shí)優(yōu)先級和nice優(yōu)先級處于互不相交的兩個(gè)范疇。

    ?

    ? ? 在Linux中,與調(diào)度相關(guān)的常見接口如下:

    ?

    [cpp] view plain copy
  • #include?<sched.h>??
  • int?sched_get_priority_max(int?policy);??
  • 該接口獲取指定調(diào)度策略可以設(shè)置的最大優(yōu)先級,類似的?sched_get_priority_min接口獲取調(diào)度策略可以設(shè)置的最小優(yōu)先級。在Linux中,對于SCHED_FIFOSCHED_RR調(diào)度策略其優(yōu)先級為199,其他調(diào)度策略優(yōu)先級為0。注意在不同系統(tǒng)上,這個(gè)優(yōu)先級范圍可能不一樣。

    ?

    [cpp] view plain copy
  • #include?<pthread.h>??
  • int?pthread_attr_setschedpolicy(pthread_attr_t?*attr,?int?policy);??
  • 該接口可以用來設(shè)置線程的調(diào)度策略,即設(shè)置線程屬性attr。參數(shù)policy可以是CHED_FIFO,?SCHED_RRSCHED_OTHER。系統(tǒng)創(chuàng)建線程時(shí),默認(rèn)的線程調(diào)度策略是SCHED_OTHER。類似可以通過接口

    ?

    [cpp] view plain copy
  • int?pthread_attr_getschedpolicy(const?pthread_attr_t?*attr,?int?*policy)??
  • 獲取線程的調(diào)度策略。

    ?

    [cpp] view plain copy
  • #include?<pthread.h>??
  • int?pthread_attr_setschedparam(pthread_attr_t?*attr,??
  • const?struct?sched_param?*param);??
  • 該接口可以用來設(shè)置線程的調(diào)度優(yōu)先級。結(jié)構(gòu)sched_param定義如下:

    ?

    [cpp] view plain copy
  • struct?sched_param?{??
  • ???int?sched_priority;?????/*?Scheduling?priority?*/??
  • };??
  • 類似的的接口,可以用來獲取線程調(diào)度的優(yōu)先級:

    ?

    [cpp] view plain copy
  • int?pthread_attr_getschedparam(const?pthread_attr_t?*attr,??
  • ??????????????????????????????????????struct?sched_param?*param);??
  • [cpp] view plain copy
  • #include?<sched.h>??
  • int?sched_yield(void);??
  • 調(diào)用該接口可以使得當(dāng)前線程主動(dòng)交出CPU,并把該線程放到相應(yīng)調(diào)度隊(duì)列的末尾。如果當(dāng)前線程是最高優(yōu)先級隊(duì)列中唯一的線程,則在調(diào)用sched_yield后,該線程繼續(xù)保持運(yùn)行。

    ?

    [cpp] view plain copy
  • #include?<sched.h>??
  • int?sched_setaffinity(pid_t?pid,???
  • ??????????????????????size_t?cpusetsize,const?cpu_set_t?*mask);??
  • 該接口可以用來設(shè)置線程的CPU親和性(CPU?affinity),設(shè)置線程的親和性可以使得線程綁定到一個(gè)或多個(gè)指定的CPU上運(yùn)行。在多處理器系統(tǒng)上,設(shè)置CPU親和性可以提高性能(主要原因是盡可能避免了cache失效和切換到其他CPU的消耗)。CPU親和性掩碼是由cpu_set_t結(jié)果來實(shí)現(xiàn)的,該結(jié)構(gòu)體需要用預(yù)定義好的宏來操作;參數(shù)pid是指定線程的TID,可以通過gettid()來獲取,即線程在內(nèi)核中對應(yīng)進(jìn)程id,若pid0,則設(shè)置的是調(diào)用線程的CPU親和性,注意用getpid()獲取的是主線程的id;參數(shù)cpusetsize的值通常是mask的大小,即sizeof(mask)。除了這個(gè)接口外,設(shè)置線程親和性接口還有:

    ?

    [cpp] view plain copy
  • #include?<pthread.h>??
  • int?pthread_setaffinity_np(pthread_t?thread,?size_t?cpusetsize,??
  • ??????????????????????????????????const?cpu_set_t?*cpuset);??
  • int?pthread_attr_setaffinity_np(pthread_attr_t?*attr,??
  • size_t?cpusetsize,?const?cpu_set_t?*cpuset);??
  • 通過fork創(chuàng)建的子進(jìn)程繼承父進(jìn)程的CPU親和性,通過?execve()后,親和性仍然保持不變。我們可以下面命令來查看多核cpu的負(fù)載:

    ? ? I)cat?/proc/cpuinfo??查看所有cpu的信息;

    ? ? II)top命令,然后再輸入1,則顯示多個(gè)cpu的使用信息;

    ? ? III)top命令,然后按下f,進(jìn)入top?Current?Fields設(shè)置頁面,然后按下j,表示要求顯示進(jìn)程使用那個(gè)cpu,回車后,回到剛才界面,此時(shí)P?顯示此進(jìn)程使用哪個(gè)CPU。

    ?

    ? ? 下面是測試代碼:

    ?

    [cpp] view plain copy
  • #include?<stdio.h>??
  • #include?<pthread.h>??
  • #include?<sched.h>??
  • #include?<assert.h>??
  • ??
  • static?int?get_thread_policy(pthread_attr_t?*attr)??
  • {??
  • ????int?policy;??
  • ????int?rs?=?pthread_attr_getschedpolicy(attr,&policy);??
  • ????assert(rs==0);??
  • ??
  • ????switch(policy)??
  • ????{?????
  • ????????case?SCHED_FIFO:??
  • ????????????printf("policy=SCHED_FIFO\n");??
  • ????????????break;??
  • ??
  • ????????case?SCHED_RR:??
  • ????????????printf("policy=SCHED_RR\n");??
  • ????????????break;??
  • ??
  • ????????case?SCHED_OTHER:??
  • ????????????printf("policy=SCHED_OTHER\n");??
  • ????????????break;??
  • ??
  • ????????default:??
  • ????????????printf("policy=UNKNOWN\n");??
  • ????????????break;??
  • ????}?????
  • ????return?policy;??
  • }??
  • ??
  • static?void?show_thread_priority(pthread_attr_t?*attr,int?policy)??
  • {??
  • ????int?priority?=?sched_get_priority_max(policy);??
  • ????assert(priority?!=?-1);??
  • ????printf("max_priority=%d\n",priority);??
  • ??
  • ????priority=?sched_get_priority_min(policy);??
  • ????assert(priority?!=?-1);??
  • ????printf("min_priority=%d\n",priority);??
  • }??
  • ??
  • static?int?get_thread_priority(pthread_attr_t?*attr)??
  • {??
  • ????struct?sched_param?param;??
  • ????int?rs?=?pthread_attr_getschedparam(attr,?m);??
  • ????assert(rs?==?0);??
  • ??
  • ????printf("priority=%d\n",param.__sched_priority);??
  • ????return?param.__sched_priority;??
  • }??
  • ??
  • static?void?set_thread_policy(pthread_attr_t?*attr,int?policy)??
  • {??
  • ????int?rs?=?pthread_attr_setschedpolicy(attr,policy);??
  • ????assert(rs==0);??
  • }??
  • ??
  • int?main(void)??
  • {??
  • ????pthread_attr_t?attr;??
  • ????int?rs;??
  • ??
  • ????rs?=?pthread_attr_init(&attr);??
  • ????assert(rs==0);??
  • ??
  • ????int?policy?=?get_thread_policy(&attr);??
  • ??
  • ????printf("Show?current?configuration?of?priority\n");??
  • ????get_thread_policy(&attr);??
  • ????show_thread_priority(&attr,policy);??
  • ??
  • ????printf("show?SCHED_FIFO?of?priority\n");??
  • ????show_thread_priority(&attr,SCHED_FIFO);??
  • ??
  • ????printf("show?SCHED_RR?of?priority\n");??
  • ????show_thread_priority(&attr,SCHED_RR);??
  • ??
  • ????printf("show?priority?of?current?thread\n");??
  • ????get_thread_priority(&attr);??
  • ??
  • ????printf("Set?thread?policy\n");??
  • ??
  • ????printf("set?SCHED_FIFO?policy\n");??
  • ????set_thread_policy(&attr,SCHED_FIFO);??
  • ????get_thread_policy(&attr);??
  • ????get_thread_priority(&attr);??
  • ??
  • ????printf("set?SCHED_RR?policy\n");??
  • ????set_thread_policy(&attr,SCHED_RR);??
  • ????get_thread_policy(&attr);??
  • ??
  • ????printf("Restore?current?policy\n");??
  • ????set_thread_policy(&attr,policy);??
  • ????get_thread_priority(&attr);??
  • ??
  • ????rs?=?pthread_attr_destroy(&attr);??
  • ????assert(rs==0);??
  • ??
  • ????return?0;??
  • }??
  • 編譯和運(yùn)行程序結(jié)果如下:

    ?

    [cpp] view plain copy
  • $gcc?-Wall?-lpthread?hack_thread_sched.c?-o?hack_thread_sched??
  • $./hack_thread_sched???
  • policy=SCHED_OTHER??
  • Show?current?configuration?of?priority??
  • policy=SCHED_OTHER??
  • max_priority=0??
  • min_priority=0??
  • show?SCHED_FIFO?of?priority??
  • max_priority=99??
  • min_priority=1??
  • show?SCHED_RR?of?priority??
  • max_priority=99??
  • min_priority=1??
  • show?priority?of?current?thread??
  • priority=0??
  • Set?thread?policy??
  • set?SCHED_FIFO?policy??
  • policy=SCHED_FIFO??
  • priority=0??
  • set?SCHED_RR?policy??
  • policy=SCHED_RR??
  • Restore?current?policy??
  • priority=0??
  • 從輸出結(jié)果,我們可以看到:

    ? ? I)線程默認(rèn)的調(diào)度策略為SCHED_OTHER,并且最大和最小調(diào)度優(yōu)先級都是0。

    ? ? II)調(diào)度策略SCHED_FIFOSCHED_RR的優(yōu)先級范圍為199,并且初始設(shè)置時(shí)對應(yīng)的調(diào)度優(yōu)先級初始值為0。

    ? ??Linux中,調(diào)度程序是一個(gè)叫schedule()的函數(shù),該函數(shù)調(diào)用的頻率很高,由它來決定是否要執(zhí)行進(jìn)程的切換,如果要切換的話,切換到那個(gè)進(jìn)程等。那么在Linux中,在什么情況下要執(zhí)行這個(gè)調(diào)度程序呢?我們把這種情況叫作調(diào)度時(shí)機(jī)。Linux調(diào)度時(shí)機(jī)主要有:

    ? ?I)進(jìn)程狀態(tài)轉(zhuǎn)換的時(shí)刻:進(jìn)程終止、進(jìn)程睡眠(比如I/O阻塞就會(huì)導(dǎo)致這種情況),還比如進(jìn)程調(diào)用sleep()或exit()等函數(shù)進(jìn)行狀態(tài)轉(zhuǎn)換。?

    ? ?II)當(dāng)前進(jìn)程的時(shí)間片用完時(shí)。

    ? ? ?III)設(shè)備驅(qū)動(dòng)程序,當(dāng)設(shè)備驅(qū)動(dòng)程序執(zhí)行長而重復(fù)的任務(wù)時(shí),在每次反復(fù)循環(huán)中,驅(qū)動(dòng)程序讀檢查是否需要調(diào)度,如果必要,則調(diào)用調(diào)度程序schedule()放棄CPU。

    ? ? ?IV)進(jìn)程從中斷、異常及系統(tǒng)調(diào)用返回到用戶態(tài)時(shí)。

    參考資料

    http://man7.org/linux/man-pages/man7/sched.7.html
    http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html
    http://www.cnblogs.com/xiaotlili/p/3510224.html
    http://www.708luo.com/?p=78 Linux
    http://www.quora.com/What-is-the-difference-between-the-NI-and-PR-values-in-the-top-1-commands-output
    http://blog.csdn.net/hanchaoman/article/details/6697636
    http://www.ibm.com/developerworks/cn/linux/l-affinity.html
    http://blog.csdn.net/chenggong2dm/article/details/6131052

    《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》(第3版)
    《深入分析Linux內(nèi)核源代碼》(陳莉君著)

    總結(jié)

    以上是生活随笔為你收集整理的浅析Linux线程调度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。