Linux :多處理器遇到實(shí)時(shí)進(jìn)程和普通進(jìn)程的程序設(shè)計(jì)
問(wèn)題很明顯:為什么 4 個(gè)線程為什么被同時(shí)執(zhí)行了?
1 號(hào)和 2 號(hào)這兩個(gè)線程應(yīng)該被優(yōu)先執(zhí)行啊,因?yàn)樗鼈z是實(shí)時(shí)任務(wù)!
怎么結(jié)果是這個(gè)樣子?徹底凌亂了,一點(diǎn)都不符合預(yù)期!
想不出個(gè)所以然,只能求助網(wǎng)絡(luò)!但是沒(méi)有找到有價(jià)值的線索。
其中有一個(gè)信息涉及到 Linux 系統(tǒng)的調(diào)度策略,這里記錄一下。
Linux 系統(tǒng)中,為了不讓實(shí)時(shí)任務(wù)徹底占據(jù) CPU 資源,會(huì)讓普通任務(wù)有很小的一段時(shí)間縫隙來(lái)執(zhí)行。
在目錄 /proc/sys/kernel 下面,有 2 個(gè)文件,用來(lái)限制實(shí)時(shí)任務(wù)占用 CPU 的時(shí)間:
sched_rt_runtime_us: 默認(rèn)值 950000sched_rt_period_us: 默認(rèn)值 1000000
意思是:在 1000000 微秒(1秒)的周期內(nèi),實(shí)時(shí)任務(wù)占用 950000 微秒(0.95秒),剩下的 0.05 秒留給普通任務(wù)。
如果沒(méi)有這個(gè)限制的話,假如某個(gè) SCHED_FIFO 任務(wù)的優(yōu)先級(jí)特別高,恰巧出了 bug:一直占據(jù) CPU 資源不放棄,那么我們壓根就沒(méi)有機(jī)會(huì)來(lái) kill 掉這個(gè)實(shí)時(shí)任務(wù),因?yàn)榇藭r(shí)系統(tǒng)無(wú)法調(diào)度其他的任何進(jìn)程來(lái)執(zhí)行。
而有了這個(gè)限制呢,我們就可以利用這 0.05 秒的執(zhí)行時(shí)間,來(lái) kill 掉有 bug 的那個(gè)實(shí)時(shí)任務(wù)。
回到正題:資料上說(shuō),如果實(shí)時(shí)任務(wù)沒(méi)有被優(yōu)先調(diào)度,可以把這個(gè)時(shí)間限制刪掉就可以了。方法是:
sysctl -w kernel.sched_rt_runtime_us=-1
我照做之后,依舊無(wú)效!
換一臺(tái)虛擬機(jī),繼續(xù)測(cè)試
難道是電腦環(huán)境的問(wèn)題嗎?于是,把測(cè)試代碼放到另一臺(tái)筆記本里的虛擬機(jī) Ubuntu14.04 里測(cè)試。
編譯的時(shí)候,有一個(gè)小問(wèn)題,提示錯(cuò)誤:
error: ‘for’ loop initial declarations are only allowed in C99 mode
只要把編譯指令中添加 C99 標(biāo)準(zhǔn)就可以了:
gcc -o test test.c -lpthread -std=c99
執(zhí)行程序,打印信息如下:
====> thread_index = 2
====> thread_index = 1
thread_index 1: SCHED_FIFO
thread_index 1: priority = 51
thread_index 2: SCHED_FIFO
thread_index 2: priority = 52
thread_index 1: num = 0
thread_index 2: num = 0
thread_index 2: num = 1
thread_index 1: num = 1
thread_index 2: num = 2
thread_index 1: num = 2
thread_index 2: num = 3
thread_index 1: num = 3
thread_index 2: num = 4
thread_index 1: num = 4
thread_index 2: num = 5
thread_index 1: num = 5
thread_index 2: num = 6
thread_index 1: num = 6
thread_index 2: num = 7
thread_index 1: num = 7
thread_index 2: num = 8
thread_index 1: num = 8
thread_index 2: num = 9
thread_index 2: exit
====> thread_index = 4
thread_index 4: SCHED_OTHER
thread_index 4: priority = 0
thread_index 1: num = 9
thread_index 1: exit
====> thread_index = 3
thread_index 3: SCHED_OTHER
thread_index 3: priority = 0
thread_index 3: num = 0
thread_index 4: num = 0
thread_index 3: num = 1
thread_index 4: num = 1
thread_index 3: num = 2
thread_index 4: num = 2
thread_index 3: num = 3
thread_index 4: num = 3
thread_index 3: num = 4
thread_index 4: num = 4
thread_index 3: num = 5
thread_index 4: num = 5
thread_index 3: num = 6
thread_index 4: num = 6
thread_index 3: num = 7
thread_index 4: num = 7
thread_index 3: num = 8
thread_index 4: num = 8
thread_index 3: num = 9
thread_index 3: exit
thread_index 4: num = 9
thread_index 4: exit
1 號(hào)和 2 號(hào)線程同時(shí)執(zhí)行,完畢之后,再 3 號(hào)和 4 號(hào)線程同時(shí)執(zhí)行。
但是這同樣也不符合預(yù)期:2 號(hào)線程的優(yōu)先級(jí)比 1 號(hào)線程高,應(yīng)該優(yōu)先執(zhí)行才對(duì)!
不知道應(yīng)該怎么查這個(gè)問(wèn)題了,想不出思路,只好請(qǐng)教 Linux 內(nèi)核的大神,建議檢查一下內(nèi)核版本。
這時(shí),我才想起來(lái)在 Ubuntu16.04 這臺(tái)虛擬機(jī)上因?yàn)槟撤N原因,降過(guò)內(nèi)核版本。
往這個(gè)方向去排查了一下,最后確認(rèn)也不是內(nèi)核版本的差異導(dǎo)致的問(wèn)題。
比較結(jié)果,尋找差異
只好再回過(guò)頭來(lái)看一下這兩次次打印信息的差異:
工作電腦里的 Ubuntu16.04 中:4 個(gè)線程同時(shí)調(diào)度執(zhí)行,調(diào)度策略和優(yōu)先級(jí)都沒(méi)有起作用;
筆記本里的 Ubuntu14.04 中:1 號(hào)和 2 號(hào)實(shí)時(shí)任務(wù)被優(yōu)先執(zhí)行了,說(shuō)明調(diào)度策略起作用了,但是優(yōu)先級(jí)沒(méi)有起作用;
突然, CPU 的親和性從腦袋里蹦了出來(lái)!
緊接著立馬感覺(jué)到問(wèn)題出在哪里了:這TMD大概率就是多核引起的問(wèn)題!
于是我把這 4 個(gè)線程都綁定到 CPU0 上去,也就是設(shè)置 CPU 親和性。
在線程入口函數(shù) thread_routine 的開(kāi)頭,增加下面的代碼:
cpu_set_t mask;
int cpus = sysconf(_SC_NPROCESSORS_CONF);
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)
{
printf("set thread affinity failed! ");
}
然后繼續(xù)在 Ubuntu16.04 虛擬機(jī)中驗(yàn)證,打印信息很完美,完全符合預(yù)期:
====> thread_index = 1
====> thread_index = 2
thread_index 2: SCHED_FIFO
thread_index 2: priority = 52
thread_index 2: num = 0
。。。
thread_index 2: num = 9
thread_index 2: exit
thread_index 1: SCHED_FIFO
thread_index 1: priority = 51
thread_index 1: num = 0
。。。
thread_index 1: num = 9
thread_index 1: exit
====> thread_index = 3
thread_index 3: SCHED_OTHER
thread_index 3: priority = 0
====> thread_index = 4
thread_index 4: SCHED_OTHER
thread_index 4: priority = 0
thread_index 3: num = 0
thread_index 4: num = 0
。。。
thread_index 4: num = 8
thread_index 3: num = 8
thread_index 4: num = 9
thread_index 4: exit
thread_index 3: num = 9
thread_index 3: exit
至此,問(wèn)題真相大白:就是多核處理器導(dǎo)致的問(wèn)題!
而且這兩臺(tái)測(cè)試的虛擬機(jī),安裝的時(shí)候分配的 CPU 核心是不同的,所以才導(dǎo)致打印結(jié)果的不同。
真相大白
最后,再確認(rèn)一下這 2 個(gè)虛擬機(jī)中的 CPU 信息:
Ubuntu 16.04 中 cpuinfo 信息:
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 4
。。。其他信息
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id : 1
cpu cores : 4
。。。其他信息
processor : 2
vendor_id : GenuineIntel
cpu family : 6
model : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id : 2
cpu cores : 4
。。。其他信息
processor : 3
vendor_id : GenuineIntel
cpu family : 6
model : 158
model name : Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz
stepping : 10
cpu MHz : 2807.996
cache size : 9216 KB
physical id : 0
siblings : 4
core id : 3
cpu cores : 4
。。。
其他信息
在這臺(tái)虛擬機(jī)中,正好有 4 個(gè)核心,而我的測(cè)試代碼正好也創(chuàng)建了 4 個(gè)線程,于是每個(gè)核心被分配一個(gè)線程,一個(gè)都不閑著,同時(shí)執(zhí)行。
因此打印信息中顯示 4 個(gè)線程是并行執(zhí)行的。
這個(gè)時(shí)候,什么調(diào)度策略、什么優(yōu)先級(jí),都不起作用了!(準(zhǔn)確的說(shuō):調(diào)度策略和優(yōu)先級(jí),在線程所在的那個(gè) CPU 中是起作用的)
如果我在測(cè)試代碼中,一開(kāi)始就創(chuàng)建 10 個(gè)線程,很可能會(huì)更快發(fā)現(xiàn)問(wèn)題!
再來(lái)看看筆記本電腦里虛擬機(jī) Ubuntu14.04 的 CPU 信息:
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
stepping : 9
microcode : 0x9a
cpu MHz : 2304.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
。。。其他信息
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
stepping : 9
microcode : 0x9a
cpu MHz : 2304.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
。。。其他信息
在這臺(tái)虛擬機(jī)中,有 2 個(gè)核心,于是 2 個(gè)實(shí)時(shí)任務(wù) 1 號(hào)和 2 號(hào)被優(yōu)先執(zhí)行(因?yàn)槭?2 個(gè)核心同時(shí)執(zhí)行,所以這 2 個(gè)任務(wù)的優(yōu)先級(jí)也就沒(méi)什么意義了),結(jié)束之后,再執(zhí)行 3 號(hào)和 4 號(hào)線程。
再思考一下
這一圈測(cè)試下來(lái),真的想用鍵盤(pán)敲自己的腦袋,怎么就沒(méi)有早點(diǎn)考慮到多核的因素呢?!
深層的原因:
之前的很多項(xiàng)目,都是 ARM、mips、STM32等單核情況,思維定式讓我沒(méi)有早點(diǎn)意識(shí)到多核這個(gè)屏體因素;
做過(guò)的一些 x86 平臺(tái)項(xiàng)目,并沒(méi)有涉及到實(shí)時(shí)任務(wù)這樣的要求。一般都是使用系統(tǒng)默認(rèn)的調(diào)度策略,這也是 Linux x86 作為通用電腦,在調(diào)度策略上所關(guān)注的重要指標(biāo):讓每一個(gè)任務(wù)都公平的使用 CPU 資源。
隨著 x86 平臺(tái)在工控領(lǐng)域的逐漸應(yīng)用,實(shí)時(shí)性問(wèn)題就顯得更突出、更重要了。
所以才有了 Windows 系統(tǒng)中的 intime,Linux 系統(tǒng)中的 preempt、xenomai 等實(shí)時(shí)補(bǔ)丁。

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
圖片新聞
-
馬云重返一線督戰(zhàn),阿里重啟創(chuàng)始人模式
-
機(jī)器人奧運(yùn)會(huì)戰(zhàn)報(bào):宇樹(shù)機(jī)器人摘下首金,天工Ultra搶走首位“百米飛人”
-
存儲(chǔ)圈掐架!江波龍起訴佰維,索賠121萬(wàn)
-
長(zhǎng)安汽車母公司突然更名:從“中國(guó)長(zhǎng)安”到“辰致科技”
-
豆包前負(fù)責(zé)人喬木出軌BP后續(xù):均被辭退
-
字節(jié)AI Lab負(fù)責(zé)人李航卸任后返聘,Seed進(jìn)入調(diào)整期
-
員工持股爆雷?廣汽埃安緊急回應(yīng)
-
中國(guó)“智造”背后的「關(guān)鍵力量」
最新活動(dòng)更多
-
10月23日火熱報(bào)名中>> 2025是德科技創(chuàng)新技術(shù)峰會(huì)
-
10月23日立即報(bào)名>> Works With 開(kāi)發(fā)者大會(huì)深圳站
-
10月24日立即參評(píng)>> 【評(píng)選】維科杯·OFweek 2025(第十屆)物聯(lián)網(wǎng)行業(yè)年度評(píng)選
-
即日-11.25立即下載>>> 費(fèi)斯托白皮書(shū)《柔性:汽車生產(chǎn)未來(lái)的關(guān)鍵》
-
11月27日立即報(bào)名>> 【工程師系列】汽車電子技術(shù)在線大會(huì)
-
12月18日立即報(bào)名>> 【線下會(huì)議】OFweek 2025(第十屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
推薦專題
- 1 特斯拉工人被故障機(jī)器人打成重傷,索賠3.6億
- 2 【行業(yè)深度研究】退居幕后四年后,張一鳴終于把算法公司變成AI公司?
- 3 人形機(jī)器人廠商,正在批量復(fù)刻宇樹(shù)G1
- 4 AI 時(shí)代,阿里云想當(dāng)“安卓” ,那誰(shuí)是“蘋(píng)果”?
- 5 華為公布昇騰芯片三年計(jì)劃,自研HBM曝光
- 6 硬剛英偉達(dá)!華為發(fā)布全球最強(qiáng)算力超節(jié)點(diǎn)和集群
- 7 機(jī)器人9月大事件|3家國(guó)產(chǎn)機(jī)器人沖刺IPO,行業(yè)交付與融資再創(chuàng)新高!
- 8 谷歌“香蕉”爆火啟示:國(guó)產(chǎn)垂類AI的危機(jī)還是轉(zhuǎn)機(jī)?
- 9 00后華裔女生靠?jī)刹緼I電影狂賺7.8億人民幣,AI正式進(jìn)軍好萊塢
- 10 美光:AI Capex瘋投不止,終于要拉起存儲(chǔ)超級(jí)周期了?