一個進程能不能在多個核上跑?

題目說的一個進程在多個核上跑的意思包括:

1。被一個核掛起後到另一個核上開始跑。

2。一個進程的多個線程同時在多個核上跑

如果可以的話,據我所知,在多核處理器中,每個核是獨享自己的寄存器,一二級緩存的,如果在多個核上跑,如何保證數據的一致性


當然能了,有現成的例子,ARM的big.LITTLE技術就能實現任務的遷移:

這個圖就是任務遷移的模型。

用「任務」的說法更準確一些,一個進程可能包含多個線程,每個線程可以看成是一個任務(Task),線程是調度的最小單位。

在大多數支持多核的操作系統上,都能實現把一個進程的多個線程放不同的核心上跑,這是沒有問題的,不同的線程通常有自己獨立的線程棧,所以除了訪問全局變數外基本上不影響。緩存問題有協議來保證一致性,更複雜的一致性問題可以用鎖來保護,當然了,鎖會降低效率那是肯定的。

1。被一個核掛起後到另一個核上開始跑。

可以,ARM上就支持這麼做,主流操作系統平台也都支持,但頻繁的任務遷移實際上是對性能有害的,一般操作系統不會頻繁的遷移任務。

對於ARM的這個模型,官方聲稱的代價是微秒級,但這個代價不包括L2 cache同步的代價,實際上在 L2 snooping階段,CPU的性能是有點差的,一般來說等待L2完全同步,大概需要毫秒級的開銷,具體要看操作系統和硬體的實現。

2。一個進程的多個線程同時在多個核上跑

據我所知,Windows和Linux目前也都支持。


保持cache一致性自然要靠cache一致性協議。cache的不一致,是因為同樣一份數據在多個cache中存在多份拷貝,如果數據在一個cache中被寫另一個cache卻不知道,就會有不一致。對於多核共享cache最基本的方法就是寫失效和寫更新兩種。每個核的專有cache要時刻監聽匯流排上的寫cache請求,一旦監聽到匯流排要寫的cache塊自己肚子里也有,就將自己肚子里的cache塊置為失效(寫失效),等到下次該塊cache miss再重新load最新的數據。或者在匯流排更新某塊的時候,剛好自己肚子里也有一份該塊的拷貝,順便把自己內部的cache塊也更新了(寫更新),就可以保證自己一直是最新的數據。

從硬體原理上來講,主要就是做到寫操作即時即刻的傳遞給所有的核/cache。寫操作一定要廣播出去,只要通知到位,就有辦法。


我的回答,可以說和cpu設計無關。既然樓主也放到「編程」這一個話題。我就想說一下編程多線程時候的memory的一點點問題。用C++11舉例。

假設2個全局變數。

std::atomic& x, y;

線程1:

x.store(1);
y.store(2);

線程2:

std::cout &<&< y.load() &<&< std::endl; std::cout &<&< x.load() &<&< std::endl;

y和x的輸出可能是0,0,可能是0,1,可能是2,1。但不可能是2,0。

這種就叫做 sequential consistency。也是最簡單的內存模型。Java假設全部內存操作都為 sequential consistent。C++11中的預設也是 sequential consistent。

具體怎麼實現呢?就是在x.store和y.store後面強行加上CPU指令,保證所有CPU核心的cache的一致性。

可見sequential consistency其實是很費的。

C++呢,你完全不添加任何cache一致性指令,只需要,

線程1:

x.store(1, std::memory_order_relaxed);
y.store(2, std::memory_order_relaxed);

線程2:

std::cout &<&< y.load(std::memory_order_relaxed) &<&< std::endl; std::cout &<&< x.load(std::memory_order_relaxed) &<&< std::endl;

這樣呢,就很有效率,但是呢,你無法保證cache一致性,就是說可能會輸出 2, 0。就是線程1中,y=2的時候x=1,但是線程2中,y=2的時候x還是0。

當然,C++11還提供了比完全sequential consistency 更有效率一點的操作,同樣能保證不會輸出2,0。

線程1:

x.store(1, std::memory_order_release);
y.store(2, std::memory_order_release);

線程2:

std::cout &<&< y.load(std::memory_order_acquire) &<&< std::endl; std::cout &<&< x.load(std::memory_order_acquire) &<&< std::endl;

具體就不說了。拋磚引玉而已。


1. 可以

2. 可以

正如題主所說,多核處理器,L1 L2為每個核私有,L3在對稱處理器上是共有,比如每兩個核共用一個L3 。

至於緩存的一致性就要靠MESI協議來保證,我們在多線程中要使用rmp() wmb()保證,防止出現題主所說的情況。


別的不知道,至少Windows下一個進程下的多個線程是可以自動分配到不同核心的。我自己的程序就是用線程池榨乾CPU資源的。


可以的。我無理論支持。但是用我最愛的xperf 跑一下,再用我最愛的wpa可視化一下,就可以看到cpu usage per thread/process/core/processor ,以及每個進程和線程在每個core/processor上的分配(windows)


CFD中的fluent計算便是用到多核並行計算的,可以選擇單核或多個核計算

雖不知原理,也不知道是不是和題主一樣的意思,但確實每天都在用多核算,自己cpu是四核的,所以每天可以有四核或以下的計算

另,教研室有大型計算機集群,計算可達到十多個核並行在一起計算一個case,但是我們還是要排隊等待…


給你推薦一本書吧,寫得超級贊!尤其是引用文獻,簡直多到逆天…

現代體系結構上的UNIX系統:內核程序員的對稱多處理和緩存技術


集群上可以實現


可以,多核多線程,操作系統自行分配


不同的線程通常有自己獨立的線程棧,所以除了訪問全局變數外基本上不影響。


跑不了,至少得再調入內存才能繼續。


可以的,比如3ds max渲染的時候就要讓你的處理器使用率達到100%,任務管理器只有一個進程就用了80%以上


在大多數支持多核的操作系統上,都能實現把一個進程的多個線程放不同的核心上跑,這是沒有問題的,不同的線程通常有自己獨立的線程棧,所以除了訪問全局變數外基本上不影響。


掛起後就從內存調出了,跑不了,至少得再調入內存才能繼續。


有人提到了,可以去看MESI協議,推薦這篇文章:Memory Barriers: a Hardware View for Software Hackers。 也可以去看看Linux文檔的Memory Barrier的部分。


。緩存問題有協議來保證一致性,更複雜的一致性問題可以用鎖來保護,當然了,鎖會降低效率那是肯定的。


題主的問題涉及兩個概念,上下文切換(context-switches),cpu遷移(cpu-migrations)。

都是操作系統做任務調度的基本功能。具體細節自己搜索吧。

使用perf stat可以看到這兩個指標。


Cache一致性問題別人已經說了。

不過你第一個描述被一個核掛起後到另一個核上跑,掛起後就從內存調出了,跑不了,至少得再調入內存才能繼續。


推薦閱讀:

中斷向量為什麼叫中斷向量?
計算機編程中經常提到的副作用,具體指的是什麼?有什麼定義嗎?
後XP 時代的一些思考
哪款經修改的安卓系統適合中老年人使用?
學堂在線和網易雲課堂的操作系統課程比較?

TAG:軟體 | 操作系統 | 中央處理器CPU | 編程 | 計算機 |