日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

5.模拟线程切换

發(fā)布時間:2025/3/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 5.模拟线程切换 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

模擬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é):

  • 線程不是被動切換的,而是主動讓出CPU
  • 線程切換并沒有使用TSS來保存寄存器,而是使用堆棧.
  • 線程切換的過程就是堆棧切換的過程
  • 以下是代碼:

    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é)

    以上是生活随笔為你收集整理的5.模拟线程切换的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。