1. 程式人生 > >Windows核心之執行緒的排程,優先順序,親緣性

Windows核心之執行緒的排程,優先順序,親緣性

1 排程

         Windows不是實時作業系統,它是搶佔式多執行緒作業系統。在假設所有優先順序相同的情況下,CPU對執行緒的排程原則是每隔20m就會切換到下一個執行緒,根據Context中的IP和SP來接著執行上次的東西。Windows永遠不會讓1個執行緒去獨佔一段時間。

2 可排程性

         系統只調用可以排程的執行緒,其實系統的大部分執行緒都是處於不可排程的狀態,要麼處於暫停的狀態,要麼處於休眠的狀態。

3 執行緒的暫停和恢復

<1>在CreateThread的時候通過制定CREATE_SUSPENDED來讓執行緒暫停執行

<2>在DWORD SuspendThread(HANDLE hThread)函式來暫停一個執行緒,最多次數為MAXIMUM_SUSPEND_COUNT(127)

<3>通過函式DWORD ResumeThread(HANDLE hThread)來喚醒執行緒

4 程序的暫停

         Windows中從來不存在程序的暫停和恢復,因為程序是不會被排程的。但是在特殊情況下Windows會凍結程序中所有的執行緒:除錯程式中處理函式WaitForDebugEvent返回的debug事件;直到呼叫ContinueDebugEvent.函式才會恢復程序中的所有執行緒。

         但是我們可以通過遍歷系統中所有的執行緒,通過檢查執行緒所屬的程序ID是否滿足指定值,就可以做到暫停所有的執行緒。

         弊端:

<1>遍歷執行緒ID時候,如果有新執行緒在建立,那麼新執行緒將不會被暫停

<2>當重新恢復執行緒的時候,可能會對新建立的沒有被暫停的執行緒去恢復

<3>遍歷執行緒ID的時候,撤銷的執行緒跟新建的執行緒可能具有具有相同的ID,這就可能導致暫停多個具有相同ID的執行緒。

         程序中所有執行緒暫停函式如下所示:

VOID SuspendProcess(DWORD dwProcessID, BOOL fSuspend) {
// Get the list of threads in the system.
HANDLE hSnapshot = CreateToolhelp32Snapshot(
TH32CS_SNAPTHREAD, dwProcessID);
if (hSnapshot != INVALID_HANDLE_VALUE) {
// Walk the list of threads.
THREADENTRY32 te = { sizeof(te) };
BOOL fOk = Thread32First(hSnapshot, &te);
for (; fOk; fOk = Thread32Next(hSnapshot, &te)) {
// Is this thread in the desired process?
if (te.th32OwnerProcessID == dwProcessID) {
// Attempt to convert the thread ID into a handle.
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME,
FALSE, te.th32ThreadID);
if (hThread != NULL) {
// Suspend or resume the thread.
if (fSuspend)
SuspendThread(hThread);
else
ResumeThread(hThread);
}
CloseHandle(hThread);
}
}
CloseHandle(hSnapshot);
}
}

5 程序的休眠

VOID Sleep(DWORD dwMilliseconds)

<1>執行緒的休眠導致執行緒在一定時間段內放棄被排程的機會

<2>執行緒休眠的時間大約是指定的時間,但是可能遠大於這個時間,這取決於作業系統

<3>引數值為INFINITE,表示系統永遠不去排程執行緒,但是這個方法不好

<4>引數為0,表示放棄此次的時間片,切換到下一個執行緒,但是執行緒可能切換到自身如果沒有同等優先順序或者更高的優先順序的存在。

6 執行緒的切換

BOOL SwitchToThread();

         當呼叫這個函式的時候,系統檢測是否有一個執行緒迫切需求CPU時間,如果沒函式就立即返回,如果有就切換到這個執行緒,即便執行緒的優先順序可能低於當前的執行緒優先順序。

         函式的功能和Sleep函式在引數值為0的時候很相似,但是不同點是SwitchToThread函式允許優先順序低的執行緒被呼叫,Sleep函式卻不行。

7 執行緒的執行時間

<1>通常的程式執行時間計算方法:

ULONGLONG qwStartTime = GetTickCount64();

// Perform complex algorithm here.

ULONGLONG qwElapsedTime = GetTickCount64()- qwStartTime;

但是這樣其實是錯誤的,因為它假設執行緒執行不被為中斷。

<2>Windows提供了一個獲取執行緒和程序時間資訊的函式GetThreadTime, GetProcessTime

BOOL GetThreadTimes(
HANDLE hThread,
PFILETIME pftCreationTim
PFILETIME pftExitTime,
PFILETIME pftKernelTime,
PFILETIME pftUserTime);

BOOL GetProcessTimes(
HANDLE hProcess,
PFILETIME pftCreationTime,
PFILETIME pftExitTime,
PFILETIME pftKernelTime,
PFILETIME pftUserTime);


<3>TSC 計時方法

         目前執行緒的計時時間方式發生了變換,和之前精度為10-15ms的內部時鐘計時器不同,系統現在採用一種Time Stamp Counter (TSC)計算時間,它表示的是自從計算機開機後執行的CPU週期個數。

         通過QueryThreadCycleTime和QueryProcessCycleTime來獲取執行緒和程序執行的週期個數。

BOOL WINAPI QueryThreadCycleTime(
 _In_   HANDLE ThreadHandle,
 _Out_  PULONG64 CycleTime      //包含使用者時間和核心時間總和的週期計數值
);
BOOL WINAPI QueryProcessCycleTime(
  _In_   HANDLE ProcessHandle,
  _Out_  PULONG64 CycleTime      //包含使用者時間和核心時間總和的週期計數值
);

<4>高精度計時方法

BOOLQueryPerformanceFrequency(LARGE_INTEGER* pliFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER*pliCount);
但是若用這兩個函式來計算執行緒的執行時間的話,前提是假設執行緒不被搶佔。

8      Context的使用

         我們說Context中存放著執行緒的狀態資訊,允許執行緒在呼叫時候繼續上次的執行。CONTEXT結構體是唯一的依賴於CPU的結構體。例如在X86體系結構中,它包含下面暫存器。

CONTEXT_CONTROL,CONTEXT_DEBUG_REGISTERS,CONTEXT_FLOATING_POINT,CONTEXT_SEGMENTS,CONTEXT_INTEGER,CONTEXT_EXTENDED_REGISTERS

例如在x86中,它如下所示:

typedef struct _CONTEXT {
//
// The flag values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a thread's context, only that
// portion of the thread's context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, only those portions of the thread's
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
//
DWORD ContextFlags;
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
DWORD    Dr0;
DWORD    Dr1;
DWORD    Dr2;
DWORD    Dr3;
DWORD    Dr6;
DWORD    Dr7;
// This section is specified/returned if theContextFlags word contains the flag //CONTEXT_FLOATING_POINT.
FLOATING_SAVE_AREA FloatSave;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_SEGMENTS.
//
DWORD   SegGs;
DWORD    SegFs;
DWORD    SegEs;
DWORD    SegDs;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_INTEGER.
//
DWORD    Edi;
DWORD    Esi;
DWORD    Ebx;
DWORD    Edx;
DWORD    Ecx;
DWORD    Eax;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_CONTROL.
//
DWORD    Ebp;
DWORD    Eip;
DWORD    SegCs;               // MUST BE SANITIZED
DWORD    EFlags;              // MUST BE SANITIZED
DWORD    Esp;
DWORD    SegSs;
//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
BYTE     ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;

我們可以對CONTEXT中暫存器的內容進行讀取和改寫,這是相當酷比的行為。

<1> 獲取CONTEXT內容

BOOL GetThreadContext(

HANDLE hThread,

PCONTEXT pContext);

示例:

CONTEXT Context;
Context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &Context);

<2>設定CONTEXT內容

BOOL SetThreadContext(

HANDLE hThread,

CONST CONTEXT *pContext);

示例:

CONTEXT Context;
SuspendThread(hThread);
Context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &Context);
Context.Eip = 0x00010000;
Context.ContextFlags = CONTEXT_CONTROL;
SetThreadContext(hThread, &Context);
ResumeThread(hThread);

9 執行緒的優先順序

<1>每個執行緒都會被賦予編號為0-31的一個優先級別,31表示最高,0表示最低

<2>只要有優先順序為31的可呼叫,就絕不會呼叫0-30的

<3>即便低優先順序正在執行,只要系統發現一個高的優先順序要執行,低的會被暫停。

<4>當系統引導時會建立一個特殊執行緒叫做0頁執行緒,是系統中唯一優先順序為0的執行緒,當系統沒有別的執行緒執行時候,0頁執行緒會負責將系統所有空閒RAM頁面置0.

10 優先順序的抽象說明

         應用程式的作用是不斷變化的,需求也是不斷變化的,今天設定的優先順序可能在在明天已經不合時宜,為了能使今天寫的程式能在以後的系統上正常的執行,所以排程演算法不能一成不變,因此為微軟給應用程式設定了一個抽象的優先級別,Windows支援6種優先級別

通過這種方式,可以簡單改變程式的優先級別就達到改變程式中所有執行緒優先級別的作用。在應用程式的基礎上再根據執行緒的優先級別,給執行緒設計優先類,一共7個如下所示:

那麼執行緒結合程序後,執行緒的優先順序如下所示:


注意:程序沒有被排程,實質上沒有優先順序可言,這裡說的程序的優先順序只是個抽象概念,通過這個抽象的優先順序,可以改變執行緒的優先順序。

11 設定程式的優先順序

<1>CreateProcess的時候,dwCreationFlags引數可以設定


<2> 子程序在執行的時候改變優先順序

BOOL SetPriorityClass(HANDLE  hProcess, DWORD  fdwPriority);

<3>命令列啟動程式

當正常啟動時候,預設程序是正常的優先順序,當用STRAT啟動程序的時候,可以附帶優先順序開關。如下所示:

C:\>START /LOW CALC.EXE

/BELOWNORMAL, /NORMAL, /ABOVENORMAL,/HIGH,  /REALTIME,這些都是可選的模式

<4> 通過工作管理員來設定程序的優先級別


<5>設定執行緒優先順序

BOOL SetThreadPriority( HANDLE hThread, int nPriority);

執行緒剛剛建立的時候,優先順序是預設的正常優先順序,設定優先順序的程式碼如下所示:

DWORD dwThreadID;
HANDLE hThread = CreateThread(NULL, 0,ThreadFunc, NULL,
CREATE_SUSPENDED, &dwThreadID);
SetThreadPriority(hThread,THREAD_PRIORITY_IDLE);
ResumeThread(hThread);
CloseHandle(hThread)

<6> 動態提高執行緒優先順序

執行緒的基本優先順序:執行緒的相對優先順序和執行緒所屬的程序的優先順序綜合考慮得到的優先順序

         系統常常要提高執行緒的優先順序等級,以便對視窗訊息或讀取磁碟等I / O事件作出響應。

         系統只能為基本優先順序等級在1至1 5之間的執行緒提高其優先順序等級

         執行緒的當前優先順序不會低於執行緒的基本優先順序

         系統決不會將執行緒的優先順序等級提高到實時範圍(高於 1 5)

如果要拒絕作業系統動態的提高執行緒的優先順序,那麼就可以使用下面的兩個函式:

BOOL SetProcessPriorityBoost(HANDLEhProcess,         BOOLbDisablePriorityBoost);
BOOL SetThreadPriorityBoost(HANDLE hThread,BOOLbDisablePriorityBoost);

檢查是否啟動自動調整優先順序,使用下面的兩個函式:

BOOL GetProcessPriorityBoost(HANDLEhProcess,PBOOL pbDisablePriorityBoost);
BOOL GetThreadPriorityBoost(HANDLE hThread,PBOOLpbDisablePriorityBoost);

<7>為前臺程序調整排程程式

         當用戶對程序的視窗進行操作時,該程序就稱為前臺程序,所有其他程序則稱為後臺程序。當然,使用者希望他正在使用的程序比後臺程序具有更強的響應性。為了提高前臺程序的響應性,Wi n d o w s能夠為前臺程序中的執行緒調整其排程演算法。對於 Windows 2000來說,系統可以為前臺程序的執行緒提供比通常多的 C P U時間量。這種調整隻能在前臺程序屬於正常優先順序類的程序時才能進行。如果它屬於其他任何優先順序類,就無法進行任何調整。

         當一個優先順序為正常的程序移到前臺時,系統便將最低、低於正常、正常、高於正常和最高等優先順序的執行緒的優先順序提高 1,優先順序為空閒和關鍵時間的執行緒的優先順序則不予提高。

         設定是否開始提高前臺排程效能的方法:

10  親緣性

         這個不多說了,就是在有多個CPU的時候,指定程序或者執行緒在哪幾個指定的CPU上執行的策略,在一定情況下可以提高CPU的使用率。









相關推薦

Windows核心執行排程優先順序親緣

1 排程          Windows不是實時作業系統,它是搶佔式多執行緒作業系統。在假設所有優先順序相同的情況下,CPU對執行緒的排程原則是每隔20m就會切換到下一個執行緒,根據Context中的IP和SP來接著執行上次的東西。Windows永遠不會讓1個執行緒去獨佔

RT-Thread核心執行排程(六)

5.執行緒切換的本質? 到現在我們知道,每個執行緒的執行需要一定的“物質”基礎。首先,需要獲得CPU的使用權,這就包括CPU內部各暫存器的使用,然後有自己獨立的棧空間,這部分的空間每個執行緒應該各自獨

Windows核心程式設計 第七章 執行排程優先順序親緣(下)

7.6 運用結構環境     現在應該懂得環境結構線上程排程中所起的重要作用了。環境結構使得系統能夠記住執行緒的狀態,這樣,當下次執行緒擁有可以執行的C P U時,它就能夠找到它上次中斷執行的地方。

Windows程式設計執行同步

Windows程式設計中執行緒同步的主要機制:互斥、事件、訊號量、可等待定時器,不說了,直接上程式碼: // ThreadSync.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <windows.h>

執行排程優先順序

linux核心排程三種策略: 1,SCHED_OTHER 分時排程策略, 2,SCHED_FIFO實時排程策略,先到先服務 3,SCHED_RR實時排程策略,時間片輪轉 分時程序則通過nice和counter值決定權值,nice越小,counter越大,被排程的概率越大,也就是曾

Java多執行執行排程(二)

(一)執行緒優先順序 執行緒優先順序用1~10表示,10表示優先順序最高,預設值是5.每個優先順序對應一個Thread類的公用靜態常量。如 public static final int MIN_PRIORITY = 1; public static final int NO

Java多執行執行排程詳解

排程的概念 給定時間結點,時間間隔,任務次數,然後自動執行任務 應用場景舉例 1.日誌清理:每隔三個月,清理公司日誌檔案 2.日誌備份:每個一週,備份公司檔案 3.工資結算:每個月29號,考勤彙報,業務結算,計算工資 排程的實現方式:

執行程式設計指南執行管理(iOSMac os )

1.執行緒成本 多執行緒會佔用記憶體和效能資源。 多執行緒另外一個需要考慮的成本是成產成本。設計一個執行緒應用有時候會需要根本性的改變你應用的資料結構的組織方式。要做這些改變可能需要避免使用同步,因為本身設計不好的應用可能會造成巨大的

Windows 核心 程序 執行 初探~

對於WIndows的初學者的我來說,執行緒、程序是一個很抽象的概念,理解他們是比較困難的。接下來我就講一下程序、執行緒的概念及關係。 查閱資料得出,在windows下這兩個概念都和系統核心物件脫不開關係。 那麼什麼是系統核心物件呢? 核心物件是系統核心分配的一個記憶體塊,該

RxJava 併發執行排程

由於 Rx 目標是用在非同步系統上並且 Rx 支援多執行緒處理,所以很多 Rx 開發者認為預設情況下 Rx 就是多執行緒的。 其實實際情況不是這樣的,Rx 預設是單執行緒的。 除非你明確的指定執行緒,否則所有 onNext/onError/onComplete

windows程式設計執行

在講執行緒池之前,我們先來看下“池”是什麼意思。 “池”,我把他歸結為一大堆的資源,比如說,記憶體,執行緒,網路連線,資料庫的連線等一系列的資源,因而與之相對應的就有,記憶體池,執行緒池,網路連線池,資料庫連線池等。 執行緒池也就是一大堆的執行緒資源,它們在程式剛開始執行的

Windows核心程式設計筆記(5)----執行排程優先順序

1、作業系統執行緒排程過程 每個執行緒都有一個上下文CONTEXT結構體,儲存線上程的核心物件中,這個上下文中儲存了執行緒上一次執行時CPU暫存器的狀態。每隔固定時間,Windows會檢視所有當前存在的執行緒核心物件,其中只有一些是可排程的。Windows在可排程的執行緒中

Windows核心程式設計筆記(七) 執行排程 優先順序 關聯性

在搶佔式多工作業系統中,執行緒的執行是有限制的,系統會排程一個執行緒在一個時間塊內佔用CPU,在時間到了之後將執行緒的上下文(CONTEXT結構,儲存執行緒切換前的CPU個暫存器的值)儲存到執行緒核心物件中,從另一個可排程執行緒的CONTEXT中獲取屬於它的CPU各暫存器

Windows核心程式設計執行

執行緒組成兩部分: 1. 一個執行緒的核心物件,作業系統用它管理執行緒。 2. 一個執行緒棧,用於維護執行緒執行時所需的所有函式引數和區域性變數。 何時建立執行緒?舉例: 作業系統的Windows Indexing Services,磁碟碎片整理程式等,都是使用多執行緒進行效能優化的

Windows高階程式設計執行核心物件的同步

使用者方式同步的優點是它的同步速度非常快。如果強調執行緒的執行速度,那麼首先應該確定使用者方式的執行緒同步機制是否適合需要。使用者方式執行緒同步機制的侷限性:1、互鎖函式家族只能在單值上執行2、關鍵程式碼段只能對單個程序中的執行緒實施同步3、關鍵程式碼段容易陷入死鎖狀態,因為

Windows核心程式設計學習六:程序優先順序組和執行優先順序

注:原始碼為學習《Windows核心程式設計》的一些嘗試,非原創。若能有助於一二訪客,幸甚。 1.基本框架 使用CreateDialog和MAKEINTERESOURCE /* * File: SchedLab.cpp * Time: 2013-04-20 * D

Windows Internals 筆記——執行優先順序

1.每個執行緒都被賦予0(最低)~31(最高)的優先順序數。當系統確定給哪個執行緒分配CPU時,它會首先檢視優先順序為31的執行緒,並以迴圈的方式進行排程。如果有優先順序為31的執行緒可供排程,那麼系統就會將CPU分配給該執行緒。在該執行緒的時間片結束時,系統檢視是否還存在另一個優先順序為31的執行緒可以執行

Java併發程式設計執行生命週期、守護執行優先順序和join、sleep、yield

Java併發程式設計中,其中一個難點是對執行緒生命週期的理解,和多種執行緒控制方法、執行緒溝通方法的靈活運用。這些方法和概念之間彼此聯絡緊密,共同構成了Java併發程式設計基石之一。 Java執行緒的生命週期 Java執行緒類定義了New、Runnable、Running Man、Blocked和Dead

Python中的多執行程式設計執行安全與鎖(一) 聊聊Python中的GIL 聊聊Python中的GIL python基礎執行鎖機制 python--threading多執行總結 Python3入門執行threading常用方法

1. 多執行緒程式設計與執行緒安全相關重要概念 在我的上篇博文 聊聊Python中的GIL 中,我們熟悉了幾個特別重要的概念:GIL,執行緒,程序, 執行緒安全,原子操作。 以下是簡單回顧,詳細介紹請直接看聊聊Python中的GIL  GIL:&n

java執行建立的兩種方式六種狀態和匿名內部類建立子類或實現類物件

一.匿名內部類建立子類或實現類物件 new Test(){} 相當於建立了Test類的子類物件 並且沒有類名 建立介面實現類 new 介面名() {};介面實現類的物件 注意 : new 後邊是類或者介面名 大括號內是類或者介面中的方法 public