Linux線程優(yōu)先級(jí)設(shè)置方式
在操作系統(tǒng)中,線程優(yōu)先級(jí)決定了線程在 CPU 調(diào)度時(shí)的重要性。較高優(yōu)先級(jí)的線程會(huì)在競(jìng)爭(zhēng) CPU 資源時(shí)被更頻繁地調(diào)度,以保證其及時(shí)響應(yīng)。
一、背景
在Linux中,線程是一種輕量級(jí)的執(zhí)行單元,可以在進(jìn)程內(nèi)獨(dú)立運(yùn)行。線程可以分為普通線程和實(shí)時(shí)線程,它們之間的區(qū)別在于其調(diào)度和優(yōu)先級(jí)設(shè)置。
SCHED_OTHER
,普通的調(diào)度(非實(shí)時(shí)線程),應(yīng)用層設(shè)置優(yōu)先級(jí)0,調(diào)度器總會(huì)給此類線程分配一定的CPU資源,只不過(guò)是被分配到的頻次和時(shí)間片長(zhǎng)度較少。每1s中實(shí)時(shí)線程和普通線程的時(shí)間比例是95 :5。
普通線程沒(méi)有固定的響應(yīng)時(shí)間要求,它們的優(yōu)先級(jí)由系統(tǒng)動(dòng)態(tài)調(diào)整。
Linux
使用CFS
調(diào)度器來(lái)管理普通線程。CFS
調(diào)度器采用一種稱為紅黑樹的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)線程的優(yōu)先級(jí)。每個(gè)線程都有一個(gè)vruntime
值,它表示線程在運(yùn)行隊(duì)列中消耗的虛擬時(shí)間。CFS
調(diào)度器會(huì)根據(jù)線程的vruntime
值來(lái)確定運(yùn)行的順序。優(yōu)先級(jí)較高的線程vruntime
值較小,因此能夠更早地獲得CPU的時(shí)間片。適用場(chǎng)景
:實(shí)時(shí)性要求不高,但要求必須能被執(zhí)行的線程。SCHED_FIFO
,搶占式調(diào)度(實(shí)時(shí)線程),實(shí)時(shí)先行,應(yīng)用層設(shè)置優(yōu)先級(jí)1-99,同一優(yōu)先級(jí)的多個(gè)線程中,一旦某個(gè)搶占式線程獲取CPU,除非被更高優(yōu)先級(jí)線程搶占(比如在非實(shí)時(shí)線程中創(chuàng)建一個(gè)更高優(yōu)先級(jí)的實(shí)時(shí)線程),或該線程主動(dòng)讓出CPU資源,否則該線程將會(huì)一直占用CPU(但總會(huì)分配一點(diǎn)資源給SCHED_OTHER非實(shí)時(shí)線程)。適用場(chǎng)景
:實(shí)時(shí)性要求高,不希望被頻繁打斷的任務(wù)。SCHED_RR
,輪詢式調(diào)度(實(shí)時(shí)線程),實(shí)時(shí)循環(huán),設(shè)置優(yōu)先級(jí)1-99,以循環(huán)方式運(yùn)行,每個(gè)線程都有一個(gè)時(shí)間片來(lái)執(zhí)行任務(wù),時(shí)間片耗盡后,該線程將被放入隊(duì)列的末尾,而較低優(yōu)先級(jí)的線程有機(jī)會(huì)執(zhí)行。適用場(chǎng)景
:實(shí)時(shí)性要求高,允許被頻繁打斷的任務(wù)。
在Linux中,可以使用sched_setscheduler函數(shù)。這個(gè)函數(shù)允許我們選擇普通線程或?qū)崟r(shí)線程。對(duì)于普通線程,可以使用nice函數(shù)來(lái)動(dòng)態(tài)調(diào)整優(yōu)先級(jí)。對(duì)于實(shí)時(shí)線程,可以使用sched_setscheduler函數(shù)來(lái)設(shè)置其類型和優(yōu)先級(jí)。
關(guān)于優(yōu)先級(jí)高低和數(shù)值大小的關(guān)系,在應(yīng)用層和內(nèi)核中二者是相反的。
設(shè)置線程的優(yōu)先級(jí)需要謹(jǐn)慎,因?yàn)檫^(guò)高的優(yōu)先級(jí)可能會(huì)導(dǎo)致系統(tǒng)資源的過(guò)度占用,從而影響其他線程和進(jìn)程的正常運(yùn)行。另外,需要注意的是,只有具有足夠權(quán)限的用戶才能設(shè)置較高的實(shí)時(shí)線程優(yōu)先級(jí)。
總結(jié)起來(lái),Linux中的線程分為普通線程和實(shí)時(shí)線程。普通線程的優(yōu)先級(jí)由系統(tǒng)動(dòng)態(tài)調(diào)整,而實(shí)時(shí)線程的優(yōu)先級(jí)由用戶顯式設(shè)置。通過(guò)合理地設(shè)置線程的優(yōu)先級(jí),可以提高系統(tǒng)的性能和響應(yīng)時(shí)間。然而,設(shè)置線程的優(yōu)先級(jí)需要慎重考慮,以避免影響其他線程和進(jìn)程的正常運(yùn)行。
二、調(diào)整普通線程的優(yōu)先級(jí)
通過(guò)系統(tǒng)命令
在 Linux 系統(tǒng)中,普通線程(非實(shí)時(shí)線程)的優(yōu)先級(jí)可以通過(guò) nice
和 renice
命令來(lái)進(jìn)行設(shè)置。這些命令允許用戶在命令行中調(diào)整線程的優(yōu)先級(jí),而無(wú)需特權(quán)。
nice
命令:nice
命令用于啟動(dòng)新的進(jìn)程并設(shè)置其優(yōu)先級(jí)。它在運(yùn)行指定命令時(shí)按照給定的優(yōu)先級(jí)進(jìn)行調(diào)度。較低的優(yōu)先級(jí)對(duì)應(yīng)較高的 nice 值,這意味著 nice 值越高,優(yōu)先級(jí)越低。
命令的基本語(yǔ)法如下:
nice -n <priority> <command>
其中,-n
后面跟著要設(shè)置的優(yōu)先級(jí)值(取值范圍一般是-20到19),然后是要執(zhí)行的命令。
例如,要以較低的優(yōu)先級(jí)(較高的 nice 值)運(yùn)行一個(gè)命令,可以使用如下命令:
nice -n 10 <command>
renice
命令:renice
命令用于修改已經(jīng)運(yùn)行的進(jìn)程的優(yōu)先級(jí)。這使得用戶可以在進(jìn)程運(yùn)行時(shí)動(dòng)態(tài)地調(diào)整其優(yōu)先級(jí),而無(wú)需停止和重新啟動(dòng)它。命令的基本語(yǔ)法如下:
renice <priority> -p <PID>
其中,<priority>
是要設(shè)置的優(yōu)先級(jí)值,<PID>
是要修改優(yōu)先級(jí)的進(jìn)程的進(jìn)程 ID。
例如,要將進(jìn)程的優(yōu)先級(jí)調(diào)整為較高,可以使用如下命令:
renice -5 -p 12345
其中 12345
是目標(biāo)進(jìn)程的進(jìn)程 ID。
通過(guò) nice
和 renice
命令,用戶可以在 Linux 系統(tǒng)中方便地設(shè)置普通線程的優(yōu)先級(jí),以滿足對(duì)執(zhí)行順序的特定要求。這種方式雖然不能達(dá)到實(shí)時(shí)線程調(diào)度的級(jí)別,但對(duì)于一般的任務(wù)調(diào)度已經(jīng)足夠有效了。
通過(guò)Linux C代碼
nice
函數(shù)用于調(diào)整進(jìn)程的調(diào)度優(yōu)先級(jí),允許進(jìn)程降低自身的優(yōu)先級(jí),從而降低對(duì)系統(tǒng)資源的競(jìng)爭(zhēng),也可以提高自身優(yōu)先級(jí)來(lái)更快地響應(yīng)。
在Linux系統(tǒng)中,nice
函數(shù)的作用是通過(guò)改變進(jìn)程的靜態(tài)優(yōu)先級(jí)值,來(lái)影響進(jìn)程在CPU上的調(diào)度順序。
下面是nice
函數(shù)的原型:
#include <unistd.h> int nice(int inc);
參數(shù) inc
是一個(gè)整數(shù),表示要增加或減少的進(jìn)程優(yōu)先級(jí)。這個(gè)值的范圍通常是 -20 到 19,其中 -20 表示最高優(yōu)先級(jí),而 19 表示最低優(yōu)先級(jí)。
nice
函數(shù)的返回值是新的進(jìn)程優(yōu)先級(jí)。如果調(diào)用成功,返回值通常是 0 到 39 之間的數(shù),其中 0 表示最高優(yōu)先級(jí),而 39 表示最低優(yōu)先級(jí)。如果調(diào)用失敗,返回值為 -1,并設(shè)置全局變量 errno
以指示錯(cuò)誤原因。
以下是一些需要注意的事項(xiàng):
- 只有具有 CAP_SYS_NICE 權(quán)限(Linux內(nèi)核中的一種權(quán)限,用于控制進(jìn)程對(duì)于設(shè)置任意nice值的能力)或者以 root 用戶身份運(yùn)行的進(jìn)程才能提高進(jìn)程的調(diào)度優(yōu)先級(jí)。通常,普通用戶只能降低自己進(jìn)程的優(yōu)先級(jí)。
nice
函數(shù)的參數(shù)inc
只是相對(duì)調(diào)整,而不是設(shè)定一個(gè)絕對(duì)的優(yōu)先級(jí)值。只能提高或降低一定的優(yōu)先級(jí),而不能直接將進(jìn)程的優(yōu)先級(jí)調(diào)整到一個(gè)特定的值。
#include <stdio.h> #include <unistd.h> #include <errno.h> int main() { // 獲取當(dāng)前進(jìn)程的優(yōu)先級(jí) int currentPriority = nice(0); if (currentPriority == -1) { perror("Failed to get current process priority"); return 1; } printf("Current process priority: %d\n", currentPriority); // 增加進(jìn)程的優(yōu)先級(jí) int newPriority = nice(-5); if (newPriority == -1) { perror("Failed to increase process priority"); return 1; } printf("Increased process priority to: %d\n", newPriority); return 0; }
在 Linux 系統(tǒng)中,除了 nice
函數(shù)之外,還有一個(gè)名為 setpriority
的系統(tǒng)調(diào)用可用于設(shè)置進(jìn)程的調(diào)度優(yōu)先級(jí)。setpriority
函數(shù)提供了更靈活的方式來(lái)設(shè)置進(jìn)程的優(yōu)先級(jí),它允許指定進(jìn)程的進(jìn)程組ID和用戶ID,而不僅僅是當(dāng)前進(jìn)程。
下面是 setpriority
函數(shù)的原型:
#include <sys/resource.h> int setpriority(int which, id_t who, int priority);
which
參數(shù)指定了誰(shuí)的優(yōu)先級(jí)要被改變。它可以是PRIO_PROCESS
(表示改變指定進(jìn)程的優(yōu)先級(jí))、PRIO_PGRP
(表示改變指定進(jìn)程組的所有進(jìn)程的優(yōu)先級(jí))或者PRIO_USER
(表示改變指定用戶的所有進(jìn)程的優(yōu)先級(jí))。who
參數(shù)是進(jìn)程、進(jìn)程組或用戶的 ID,用于指定要進(jìn)行優(yōu)先級(jí)調(diào)整的目標(biāo)。priority
參數(shù)是新的進(jìn)程優(yōu)先級(jí)。其取值范圍與nice
函數(shù)相同,通常為 -20 到 19。
下面是 setpriority
函數(shù)的一個(gè)簡(jiǎn)單示例:
#include <stdio.h> #include <sys/resource.h> #include <unistd.h> #include <errno> int main() { // 設(shè)置當(dāng)前進(jìn)程的優(yōu)先級(jí) if (setpriority(PRIO_PROCESS, 0, 10) == -1) { perror("Failed to set process priority"); return 1; } printf("Process priority set to 10\n"); return 0; }
在這個(gè)示例中,setpriority
函數(shù)被用來(lái)將當(dāng)前進(jìn)程的優(yōu)先級(jí)設(shè)置為 10。這將影響當(dāng)前進(jìn)程的調(diào)度優(yōu)先級(jí)。setpriority
函數(shù)的使用可以讓我們更加靈活地控制進(jìn)程的調(diào)度優(yōu)先級(jí),可以針對(duì)不同的進(jìn)程組或用戶進(jìn)行設(shè)置,提供了比 nice
函數(shù)更細(xì)粒度的控制能力。
三、調(diào)整實(shí)時(shí)線程的優(yōu)先級(jí)
通過(guò)系統(tǒng)命令
chrt
是一個(gè)用于改變進(jìn)程調(diào)度策略或優(yōu)先級(jí)的命令行工具。它在 Linux 系統(tǒng)中提供了對(duì)實(shí)時(shí)進(jìn)程調(diào)度的控制。
chrt
命令的基本語(yǔ)法如下:
chrt [options] priority command
chrt
命令的常用選項(xiàng)包括:
-p, --pid
:指定要操作的進(jìn)程ID。-f, --fifo
:設(shè)置進(jìn)程的調(diào)度策略為 FIFO(先進(jìn)先出)。-r, --rr
:設(shè)置進(jìn)程的調(diào)度策略為 Round Robin(循環(huán)調(diào)度)。-o, --other
:設(shè)置進(jìn)程的調(diào)度策略為其他進(jìn)程調(diào)度策略。-m, --max
:設(shè)置進(jìn)程的優(yōu)先級(jí)為最高優(yōu)先級(jí)。-e, --min
:設(shè)置進(jìn)程的優(yōu)先級(jí)為最低優(yōu)先級(jí)。-p, --priority priority
:設(shè)置進(jìn)程的靜態(tài)優(yōu)先級(jí)。
- 以下是幾個(gè)使用示例:
將進(jìn)程的調(diào)度策略設(shè)置為 FIFO(先進(jìn)先出):
chrt -f -p 90 <command>
將進(jìn)程的調(diào)度策略設(shè)置為 Round Robin(循環(huán)調(diào)度):
chrt -r -p 80 <command>
將進(jìn)程的調(diào)度策略設(shè)置為其他調(diào)度策略(如 SCHED_BATCH):
chrt -o -p 50 <command>
將進(jìn)程的優(yōu)先級(jí)設(shè)置為最高優(yōu)先級(jí):
chrt -m -p 99 <command>
將進(jìn)程的優(yōu)先級(jí)設(shè)置為最低優(yōu)先級(jí):
chrt -e -p 0 <command>
在上述示例中,<command>
是要運(yùn)行的命令或進(jìn)程。通過(guò)使用不同的選項(xiàng)和參數(shù),chrt
命令可以改變進(jìn)程的調(diào)度策略和優(yōu)先級(jí),從而影響進(jìn)程在系統(tǒng)中的調(diào)度行為。
請(qǐng)注意,使用 chrt
命令可能需要 root 權(quán)限或 CAP_SYS_NICE 權(quán)限。
通過(guò)Linux C代碼
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sched.h> #define THREAD_PRIORITY 80 // 設(shè)置實(shí)時(shí)線程的優(yōu)先級(jí) void* thread_function(void* arg) { // 實(shí)時(shí)線程的具體操作 // ... return NULL; } int main() { pthread_t tid; pthread_attr_t attr; struct sched_param sched_param; // 初始化線程屬性 pthread_attr_init(&attr); // 設(shè)置線程為實(shí)時(shí)線程 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // 設(shè)置線程優(yōu)先級(jí) sched_param.sched_priority = THREAD_PRIORITY; pthread_attr_setschedparam(&attr, &sched_param); // 創(chuàng)建實(shí)時(shí)線程 int result = pthread_create(&tid, &attr, thread_function, NULL); if (result != 0) { fprintf(stderr, "Failed to create thread\n"); exit(EXIT_FAILURE); } // 等待實(shí)時(shí)線程結(jié)束 pthread_join(tid, NULL); // 清理資源 pthread_attr_destroy(&attr); return 0; }
pthread_attr_setinheritsched
函數(shù)用于設(shè)置線程屬性的繼承調(diào)度策略。具體來(lái)說(shuō),它可以控制新創(chuàng)建線程是否繼承調(diào)用線程的調(diào)度策略。函數(shù)原型如下:
#include <pthread.h> int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
attr
是一個(gè)指向線程屬性對(duì)象的指針,inherit
參數(shù)用于設(shè)置繼承調(diào)度策略。inherit
可以是以下兩個(gè)常量之一:
PTHREAD_INHERIT_SCHED
:新線程將繼承創(chuàng)建它的線程的調(diào)度策略。PTHREAD_EXPLICIT_SCHED
:使用顯式調(diào)度策略,即通過(guò)pthread_attr_setschedpolicy
設(shè)置特定的調(diào)度策略。
默認(rèn)情況下,線程屬性的繼承調(diào)度策略是 PTHREAD_INHERIT_SCHED
,意味著新創(chuàng)建的線程將繼承調(diào)用線程的調(diào)度策略。
下面是一個(gè)示例代碼,演示如何使用 pthread_attr_setinheritsched
函數(shù)來(lái)設(shè)置線程屬性的繼承調(diào)度策略:
#include <stdio.h> #include <pthread.h> int main() { pthread_attr_t attr; int ret; int inherit; // 初始化線程屬性 pthread_attr_init(&attr); // 獲取當(dāng)前線程屬性的繼承調(diào)度策略 ret = pthread_attr_getinheritsched(&attr, &inherit); if (ret == 0) { if (inherit == PTHREAD_INHERIT_SCHED) { printf("繼承調(diào)度策略:PTHREAD_INHERIT_SCHED\n"); } else if (inherit == PTHREAD_EXPLICIT_SCHED) { printf("繼承調(diào)度策略:PTHREAD_EXPLICIT_SCHED\n"); } else { printf("未知的繼承調(diào)度策略\n"); } } else { printf("獲取線程屬性的繼承調(diào)度策略失敗\n"); } // 設(shè)置線程屬性的繼承調(diào)度策略 inherit = PTHREAD_EXPLICIT_SCHED; ret = pthread_attr_setinheritsched(&attr, inherit); if (ret == 0) { printf("成功設(shè)置線程屬性的繼承調(diào)度策略\n"); } else { printf("設(shè)置線程屬性的繼承調(diào)度策略失敗\n"); } // 銷毀線程屬性 pthread_attr_destroy(&attr); return 0; }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Nginx出現(xiàn)500 Internal Server Error 錯(cuò)誤的解決方案
這篇文章主要介紹了Nginx出現(xiàn)500 Internal Server Error 錯(cuò)誤的解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11在 Linux 終端中查找域名 IP 地址的命令(五種方法)
本教程介紹了如何在 Linux 終端驗(yàn)證域名或計(jì)算機(jī)名的 IP 地址。我們將教你如何有效使用這些命令在 Linux 終端中識(shí)別多個(gè)域的 IP 地址信息2019-12-12Wampserver2.5配置虛擬主機(jī)出現(xiàn)403 Forbidden的處理方案
WampServer是一款由法國(guó)人開發(fā)的Apache Web服務(wù)器、PHP解釋器以 及MySQL數(shù)據(jù)庫(kù)的整合軟件包。免去了開發(fā)人員將時(shí)間花費(fèi)在繁瑣的配置環(huán)境過(guò)程,從而騰出更多精力去做開發(fā)。在windows下將Apache+PHP+Mysql 集成環(huán)境,擁有簡(jiǎn)單的圖形和菜單安裝和配置環(huán)境。2014-09-09Apache Rewrite url重定向功能的簡(jiǎn)單配置
Rewrite url重定向就是實(shí)現(xiàn)URL的跳轉(zhuǎn)和隱藏真實(shí)地址,基于Perl語(yǔ)言的正則表達(dá)式規(guī)范。平時(shí)幫助我們實(shí)現(xiàn)擬靜態(tài),擬目錄,域名跳轉(zhuǎn),防止盜鏈等2010-08-08Linux基于環(huán)形隊(duì)列的生產(chǎn)消費(fèi)者模型詳解
這篇文章主要介紹了Linux基于環(huán)形隊(duì)列的生產(chǎn)消費(fèi)者模型方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04怎樣給centos系統(tǒng)擴(kuò)展磁盤分區(qū)的實(shí)現(xiàn)方法
這篇文章主要介紹了怎樣給centos系統(tǒng)擴(kuò)展磁盤分區(qū)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12deepin20 安裝英偉達(dá)閉源驅(qū)動(dòng)的步驟詳解
這篇文章主要介紹了deepin20 安裝英偉達(dá)閉源驅(qū)動(dòng)的步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09