5.模拟线程切换
模擬Windows線程切換(ThreadSwitch)
正在運(yùn)行的線程在KPCR里,等待的線程在等待鏈表中,調(diào)度中的線程在那32個調(diào)度鏈表中。
創(chuàng)建它是從下標(biāo)1的位置開始存的而不是0,因為main需要一個線程。
創(chuàng)建的線程還不能調(diào)度還需要初始化的環(huán)境,寄存器的值、當(dāng)前線程的堆棧要確定
模擬線程切換總結(jié):
以下是代碼:
ThreadSwitch.h
#pragma once #include <windows.h> #include "stdio.h"//最大支持的線程數(shù) #define MAXGMTHREAD 100//線程信息的結(jié)構(gòu) typedef struct {char* name; //線程名 相當(dāng)于線程IDint Flags; //線程狀態(tài)int SleepMillsecondDot; //休眠時間void* initialStack; //線程堆棧起始位置void* StackLimit; //線程堆棧界限void* KernelStack; //線程堆棧當(dāng)前位置,也就是ESPvoid* lpParameter; //線程函數(shù)的參數(shù)void(*func)(void* lpParameter); //線程函數(shù) }GMThread_t;void GMSleep(int MilliSeconds); int RegisterGMThread(char* name, void(*func)(void*lpParameter), void* lpParameter); void Scheduling();ThreadSwitch.c
#include "ThreadSwitch.h"//定義線程棧的大小 #define GMTHREADSTACKSIZE 0x80000//當(dāng)前線程的索引 int CurrentThreadIndex = 0;//線程的列表 GMThread_t GMThreadList[MAXGMTHREAD] = { NULL, 0 };//線程狀態(tài)的標(biāo)志 enum FLAGS {GMTHREAD_CREATE = 0x1,GMTHREAD_READY = 0x2,GMTHREAD_SLEEP = 0x4,GMTHREAD_EXIT = 0x8, };//啟動線程的函數(shù) void GMThreadStartup(GMThread_t* GMThreadp) {GMThreadp->func(GMThreadp->lpParameter);GMThreadp->Flags = GMTHREAD_EXIT;Scheduling();return; }//空閑線程的函數(shù) void IdleGMThread(void* lpParameter) {printf("IdleGMThread---------------\n");Scheduling();return; }//向棧中壓入一個uint值 void PushStack(unsigned int** Stackpp, unsigned int v) {*Stackpp -= 1;//esp - 4**Stackpp = v;//return; }//初始化線程的信息 void initGMThread(GMThread_t* GMThreadp, char* name, void(*func)(void* lpParameter), void* lpParameter) {unsigned char* StackPages;unsigned int* StackDWordParam;//結(jié)構(gòu)初始化賦值GMThreadp->Flags = GMTHREAD_CREATE;GMThreadp->name = name;GMThreadp->func = func;GMThreadp->lpParameter = lpParameter;//申請空間StackPages = (unsigned char*)VirtualAlloc(NULL, GMTHREADSTACKSIZE, MEM_COMMIT, PAGE_READWRITE);//初始化ZeroMemory(StackPages, GMTHREADSTACKSIZE);//初始化地址地址GMThreadp->initialStack = StackPages + GMTHREADSTACKSIZE;//堆棧限制GMThreadp->StackLimit = StackPages;//堆棧地址StackDWordParam = (unsigned int*)GMThreadp->initialStack;//入棧PushStack(&StackDWordParam, (unsigned int)GMThreadp); //通過這個指針來找到線程函數(shù),線程參數(shù)PushStack(&StackDWordParam, (unsigned int)0); //平衡堆棧的(不用管)PushStack(&StackDWordParam, (unsigned int)GMThreadStartup); //線程入口函數(shù) 這個函數(shù)負(fù)責(zé)調(diào)用線程函數(shù)PushStack(&StackDWordParam, (unsigned int)5); //push ebpPushStack(&StackDWordParam, (unsigned int)7); //push ediPushStack(&StackDWordParam, (unsigned int)6); //push esiPushStack(&StackDWordParam, (unsigned int)3); //push ebxPushStack(&StackDWordParam, (unsigned int)2); //push ecxPushStack(&StackDWordParam, (unsigned int)1); //push edxPushStack(&StackDWordParam, (unsigned int)0); //push eax//當(dāng)前線程的棧頂GMThreadp->KernelStack = StackDWordParam;//當(dāng)前線程狀態(tài)GMThreadp->Flags = GMTHREAD_READY;return; }//將一個函數(shù)注冊為單獨線程執(zhí)行 int RegisterGMThread(char* name, void(*func)(void*lpParameter), void* lpParameter) {int i;for (i = 1; GMThreadList[i].name; i++) {if (0 == _stricmp(GMThreadList[i].name, name)) {break;}}initGMThread(&GMThreadList[i], name, func, lpParameter);return (i & 0x55AA0000); }//切換線程 1:當(dāng)前線程結(jié)構(gòu)體指針 2:要切換的線程結(jié)構(gòu)體指針 __declspec(naked) void SwitchContext(GMThread_t* SrcGMThreadp, GMThread_t* DstGMThreadp) {__asm {//提升堆棧push ebpmov ebp, esp//保存當(dāng)前線程寄存器push edipush esipush ebxpush ecxpush edxpush eaxmov esi, SrcGMThreadpmov edi, DstGMThreadpmov[esi + GMThread_t.KernelStack], esp//經(jīng)典線程切換,另外一個線程復(fù)活mov esp, [edi + GMThread_t.KernelStack]pop eaxpop edxpop ecxpop ebxpop esipop edipop ebpret //把startup(線程函數(shù)入口)彈到eip 執(zhí)行的就是線程函數(shù)了} }//這個函數(shù)會讓出cpu,從隊列里重新選擇一個線程執(zhí)行 void Scheduling() {int TickCount = GetTickCount();GMThread_t* SrcGMThreadp = &GMThreadList[CurrentThreadIndex];GMThread_t* DstGMThreadp = &GMThreadList[0];for (int i = 1; GMThreadList[i].name; i++){if (GMThreadList[i].Flags & GMTHREAD_SLEEP) {if (TickCount > GMThreadList[i].SleepMillsecondDot) {GMThreadList[i].Flags = GMTHREAD_READY;}}if (GMThreadList[i].Flags & GMTHREAD_READY) {DstGMThreadp = &GMThreadList[i];break;}}CurrentThreadIndex = DstGMThreadp - GMThreadList;SwitchContext(SrcGMThreadp, DstGMThreadp);return; }void GMSleep(int MilliSeconds) {GMThread_t* GMThreadp;GMThreadp = &GMThreadList[CurrentThreadIndex];if (GMThreadp->Flags != 0) {GMThreadp->Flags = GMTHREAD_SLEEP;GMThreadp->SleepMillsecondDot = GetTickCount() + MilliSeconds;}Scheduling();return; }main.c
#include "ThreadSwitch.h"extern int CurrentThreadIndex;extern GMThread_t GMThreadList[MAXGMTHREAD];void Thread1(void*) {while (1) {printf("Thread1\n");GMSleep(500);} }void Thread2(void*) {while (1) {printf("Thread2\n");GMSleep(200);} }void Thread3(void*) {while (1) {printf("Thread3\n");GMSleep(10);} }void Thread4(void*) {while (1) {printf("Thread4\n");GMSleep(1000);} }int main() {RegisterGMThread("Thread1", Thread1, NULL);RegisterGMThread("Thread2", Thread2, NULL);RegisterGMThread("Thread3", Thread3, NULL);RegisterGMThread("Thread4", Thread4, NULL);for (;;){Sleep(20);Scheduling();}return 0; }總結(jié)
- 上一篇: 4.等待链表与调度链表
- 下一篇: 12.进程挂靠