1. 程式人生 > >windows執行緒Context

windows執行緒Context

執行緒;作業系統會維護該執行緒的CPU暫存器的狀態,該結構為上下文結構。Context

執行緒建立時可以指定執行緒為暫停狀態,這樣作業系統在排程時便不會進行排程該執行緒。

當執行緒的執行壞境作出修改時,必須是執行緒成為可排程程序。ResumeThread如果該函式執行成功返回執行緒的前一個暫停計數。

 

每個執行緒核心物件都維護著一個CONTEXT結構,裡面儲存了執行緒執行的狀態,執行緒也就是eip。

使得CPU可以記得上次執行該執行緒執行到哪裡了,該從哪裡開始執行,該執行緒內部資料如何如何。

該結構是與CPU有關的,特定的CPU對應著特定的CONTEXT結構。

x86型別CPU對應的CONTEXT結構文件如下:

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 the

    // ContextFlags 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結構中,儲存著直接和CPU有關的資訊:

 

1、ContextFlags,在查詢的時候需要設定該欄位,表示查詢哪些其他的CONTEXT結構欄位。

2、除錯暫存器組

3、FLOATING_SAVE_AREA FloatSave —— 浮點暫存器

4、段暫存器

5、通用資料暫存器(整型暫存器)組

6、控制暫存器組——比如CS、BP、SP之類的儲存基址指標和堆疊指標、程式計數器。

7、BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION] —— 擴充套件暫存器組

 

可以查詢CONTEXT結構中的內容。如上所述,通過設定CONTEXT中的ContextFlags欄位,選擇要查詢的內容:

 

1、CONTEXT_DEBUG_REGISTERS,查詢調式暫存器

2、CONTEXT_FLOATING_POINT,查詢浮點暫存器

3、CONTEXT_SEGMENTS,查詢段暫存器

4、CONTEXT_INTEGER,查詢通用資料暫存器

5、CONTEXT_CONTROL,查詢控制暫存器組

6、CONTEXT_EXTENDED_REGISTERS,擴充套件暫存器組

 

在查詢之前,先呼叫SuspendThread函式暫停一個執行緒的執行,然後呼叫GetThreadContext函式取得CONTEXT結構中相關內容。

 

下面程式碼查詢一個執行緒的控制暫存器組資訊:

CONTEXT Context;

SuspendThread(hThread);   

Context.ContextFlags = CONTEXT_CONTROL;

GetThreadContext(hThread, &Context);    

Context.Eip = 0x00010000;     

Context.ContextFlags = CONTEXT_CONTROL;     

SetThreadContext(hThread, &Context);    

ResumeThread(hThread);   

也就是說執行緒也是一個結構體,只是在高2g的記憶體中,我們無法訪問,執行緒也就是eip,當20毫秒的時間片用完時,切換到其它執行緒,

當執行完時,在context結構中取出儲存的第一個執行緒執行結束時的狀態,繼續執行。

 

執行緒同步的方式

關鍵程式碼段 使用者方式 優點速度快 缺點 無法設定關鍵程式碼段的超時值

EnterCriticalSection LeaveCriticalSection 在使用之前需要宣告一個critical_section的結構

在使用結構之前必須先進行初始化操作InitializeCriticalSection

在不使用這個結構時使用deleteCriticalSection

當一個執行緒試圖進入另一個執行緒擁有的關鍵程式碼段時,呼叫執行緒就立即被置於等待狀態,意味著會從使用者態轉換為核心態,代價是十分大的,因此使用迴圈鎖。InitializeCriticalSectionAndSpinCount第二個引數為迴圈等待的次數,在單核處理器下該值無效。初始化操作失敗會出現STATUS_NO_MEMOR異常

4000 通常情況下建議使用CriticalSectionAndSpinCount