核心编程随笔7——线程调度和优先级

NOTE0——何为上下文切换

每一个线程都有一个上下文后者保存在线程的内核对象中这个上下文反映了线程上一次执行时cpu寄存器的状态。大约每隔20ms(GetSystemTimeAdjustMent函数第二个参数的返回值),windows都会查看所有当前存在的线程内核对象,这些对象中只有一些是认为可以调度的。window在可调度的线程内核对象中选择一个,并将上次保存在线程上下文中的值载入cpu寄存器。这一操作成为上下文切换,可以通过spy++看线程属性。

说明:怎么确保某个线程在数据到达串行端口来的1MS之内开始运行。答案:不行。实时操作系统可以。但是window不是实时的。实时操作系统需要对底层的硬件有清楚的了解,从而指导硬盘控制器。键盘等的延时。

NOTE1——线程的挂起和恢复

有些线程对象的挂起技术大于0,这意味着该线程已经被挂起。不应该给他调度任何cpu时间。可以通过调用CreateProcess或CreateThread函数并传入CREATE_SUSPENDED标志来创建一个被挂起的线程。

可以通过调用ResumeThread函数。传入调用CreateThread时所返回的线程句柄来实现:

DWORD ResumeThread(Handle hThread);如果成功返回线程前一个挂起计数。否则返回0xffffffff,还可以通过SuspendThread来挂起线程DWORD SuspendThread(Handle hThread);任何线程都可以调用这个函数挂起另一个线程,线程可以将自己挂起。但是他无法自己恢复。实际开发中。应用程序在调用suspendthread时必须小心。因为试图挂起一个线程时。我们不知道线程在做什么。例如线程正在分配堆中的内存。线程将锁定堆。当其他线程要访问堆的时候。他们的执行将被中止。直到第一个线程恢复。之后又在确切知道目标线程是哪个。而且采用完备的措施避免出现因挂起线程而引起的问或死锁的时候。调用suspendthread才是安全的。

openThread这个函数将找到线程ID匹配的线程内核对象。并将内核对象的使用计数递增1,然后返回对象的句柄。有了这个句柄。就可以调用suspendthread或resumethread了

NOTE2——切换到另一个线程

SwitchToThread的函数。如果存在另一个可调度线程。那么系统会让此线程运行。调用这个函数时。系统查看是否存在正急需cpu时间的饥饿线程。如果没有立即返回。如果存在.switchtothread将调用该线程。(该优先级可能比swithtothread的主调线程低),

NOTE3——在实际上下文中谈context结构。

系统使用context结构记住线程的状态。这样线程在下一次获得cpu可以运行时。就可以在上次停止处继续。window实际上允许我们查看线程内核对象的内部。并获得当前cpu寄存器状态的集合。为此。只需要调用GetThreadContext:调用它之前应该先调用suspendthread,否则。系统可能正好获得调度此线程。这样一来。线程的上下文和所获得的信息就不一致了。一个线程实际有两个上下文。用户模式和内核模式。GetThreadContext只能返回用户模式上下文。

通过setthreadcontext来改变结构中的成员。并把新的寄存器值放回线程的内核对象中。同样如果要改变哪个线程的上下文。应该要暂停该线程。否则结果无法预料。

#include "windows.h"
#include<TLHELP32.H>
#include "stdio.h"
#include "winnt.h"
void SuspendProcess(DWORD dwProcessId,BOOL fsuspend);
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE,
PSTR pszCmdLine, int nCmdShow)
 
{
        HANDLE snapshot;  
        PROCESSENTRY32 processinfo ;  
        processinfo.dwSize=sizeof(processinfo) ;  
        snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 
        if(snapshot==NULL) 
             return FALSE;  
             BOOL status= Process32First(snapshot,&processinfo);  
             while(status)  
            {  
                    if(stricmp("notepad.exe",processinfo.szExeFile)==0) 
                         break;  
                         status=Process32Next(snapshot,&processinfo);
            }  
           if(status==0)
           {
                  MessageBox(NULL,"没有找到你要挂起的进程","提示",MB_OK);
                  return 1;
           }
           CloseHandle(snapshot);
           SuspendProcess(processinfo.th32ProcessID,1);
           SuspendProcess(processinfo.th32ProcessID,0);
           return 1;
}
void SuspendProcess(DWORD dwProcessId,BOOL fsuspend)
{
      HANDLE snapshot;  
      snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
      THREADENTRY32 te={ sizeof(te)};
      BOOL fOK=Thread32First(snapshot,&te);
      for(;fOK;fOK=Thread32Next(snapshot,&te))
     {
             if(te.th32OwnerProcessID==dwProcessId)
             {
                     typedef HANDLE (__stdcall *OPENTHREAD) (DWORD dwFlag, BOOL bUnknow, DWORD dwThreadId);  
                    HMODULE hDll =::LoadLibrary("Kernel32.dll");  
                    OPENTHREAD lpfnOpenThread = (OPENTHREAD)::GetProcAddress(hDll, "OpenThread");  
                    HANDLE hThread = lpfnOpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
                   // HANDLE hThread = lpfnOpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                   if(fsuspend==1)
                  {
                         SuspendThread(hThread);
                         CONTEXT context;
                         context.ContextFlags=CONTEXT_FULL;
                         GetThreadContext(hThread,&context);
                         context.Eip=0x00010000;
                         context.ContextFlags=CONTEXT_CONTROL;
                         SetThreadContext(hThread,&context);
                   }
                   else
                        ResumeThread(hThread);
                   // HANDLE hThread=OpenThread (THREAD_SUSPEND_RESUME,FALSE,te.th32OwnerProcessID);
         }
    }
    CloseHandle(snapshot);
}

NOTE4——优先级编程

调用createprocess中可以在fdwcreate参数中传入需要的优先级。一旦进程运行。可以通过setpriorityclass来改变自己的优先级

SetPriorityClass进行设置

SetPriorityClass

设置优先权

函数原型:

BOOL SetPriorityClass(  HANDLE hProcess,  DWORD dwPriorityClass);

GetPriorityClass

得到优先权

函数原型:

DWORD GetPriorityClass(
  HANDLE hProcess
);

dwPriorityClass:

ABOVE_NORMAL_PRIORITY_CLASS        0x00008000
BELOW_NORMAL_PRIORITY_CLASS      0x00004000
HIGH_PRIORITY_CLASS                             0x00000080

IDLE_PRIORITY_CLASS                              0x00000040
NORMAL_PRIORITY_CLASS                      0x00000020

REALTIME_PRIORITY_CLASS                   0x00000100

例:

if (!CreateProcess("D:\\Program Files\\TTPlayer\\TTPlayer.exe", GetCommandLine(), NULL,
     NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
 {
 
  CloseHandle(pi.hThread);
  WaitForSingleObject(pi.hProcess, INFINITE);
  CloseHandle(pi.hProcess);
 }

BOOL fTemp = SetPriorityClass(pi.hProcess, HIGH_PRIORITY_CLASS);
 //BOOL fTemp = SetPriorityClass(pi.hProcess, 21);
 LONG lRet = GetPriorityClass(pi.hProcess);

用来获取进程优先级的相应函数如下。getpriorityclass

NOTE5

SetProcessPriorityBoost允许或禁止系统提升一个进程中所有线程的优先级。

而SetThreadPriorityBoost则允许或禁止提升某个线程的优先级。有相应的Get函数来判断当前时候启用优先级提升。

SetFileInformationByHandle:Sets the file information for the specified file.BOOL WINAPI SetFileInformationByHandle(
  __in  HANDLE hFile,
  __in  FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
  __in  LPVOID lpFileInformation,
  __in  DWORD dwBufferSize
);

系统在启动时将确定计算机中存在多少个cpu。应用程序可以通过调用GetsystemInfo来查询机器上cpu的数量如果限制某些进程只在可用cpu的一个子集上运行。则可以调用SetProcessAffinityMask

The SetProcessAffinityMask function sets a processor affinity mask for the threads of the specified process.


BOOL SetProcessAffinityMask(
  HANDLE hProcess,
  DWORD_PTR dwProcessAffinityMask
);

 
     //get system info
    SYSTEM_INFO SystemInfo;
    GetSystemInfo(
&SystemInfo);

    printf(
" "
        
"dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, "
        
"wProcessorArchitecture=%u, dwPageSize=%u ",
        SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel, 
        SystemInfo.wProcessorArchitecture,SystemInfo.dwPageSize
        );
    
if(SystemInfo.dwNumberOfProcessors <= 1return;

    DWORD dwMask 
= 0x0000;
    DWORD dwtmp 
= 0x0001;
    
int nProcessorNum = 0;
    
for(int i = 0; i < 32; i++)
    
...{
        
if(SystemInfo.dwActiveProcessorMask & dwtmp)
        
...{
            nProcessorNum
++;
            
if(nProcessorNum <= 2)
            
...{
                
//如果系统中有多个处理器,则选择第二个处理器
                dwMask = dwtmp;
            }

            
else
            
...{
                
break;
            }

        }


        dwtmp 
*= 2;

    }
//end of for

    
//进程与指定cpu绑定
    SetProcessAffinityMask(GetCurrentProcess(), dwMask);
    
//线程与指定cpu绑定
    
//SetThreadAffinityMask(GetCurrentThread(),dwMask);

    
return ;

 

 SetThreadAffinityMask是设置此线程只能在某个或某些处理器上运行;SetThreadIdealProcessor是在上述设置的范围内,指定线程优先在某个处理器上运行

 当vista在x86计算机上启动时。我们可以限制系统将所有的cpu数量。在启动过程中。系统将检查启动配置数据(BCD),BCD是一个取代老的boot.ini文本文件的数据存库,他在计算机的硬件和固件之上提供了一个抽象层。BCD的编程配置是通过wmi实现的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022年11月4日-2022年11月14日购买当前课程赠送课程学习地址如下:https://edu.csdn.net/course/detail/32434https://edu.csdn.net/course/detail/35658https://edu.csdn.net/course/detail/30223https://edu.csdn.net/course/detail/32408https://edu.csdn.net/course/detail/32429注:因赠送课程不会出现在已订阅课程列表中,以下课程学习地址一定要收藏保存。#课程服务 在线答疑:本课程设有专门的讨论留言区,学习中遇到任何问题,直接给老师留言即可,老师都会及时进行回复。远程协助:如果遇到复杂问题,老师还可进行远程协助,这个一般可不是一两百元的课程就能享受到的。源码分享:为了让大家更好的进行项目实战,老师还将课程中涉及到的所有源码分享给学员,按照视频中的提示进行下载即可。在CSDN分享C++ Qt开发知识已经有6年了,感谢众多博友对我的支持,了解到很多人对Qt的使用还是有些困扰,例如Qt环境搭建,Qt布局的使用,如何使用Qt编写复杂的界面,如何自定义非标控件,Qt如何和Web交互,Qt和后台接口如何交互等;经过这几年的整理,我决定出这套《Qt高级开发视频教程》,带领大家学习Qt高级开发知识,学习如何使用Qt开发企业级别的项目;通过本课程的学习,大家将会达到企业招聘的中高级要求。为了照顾零基础学员,本课程第一章会介绍Qt环境搭建、QtCreator / VS2019的基本使用方法,Qt整体架构、Qt信号机制,Qt内存管理等知识。即使没有Qt开发的学习经验,也能跟着课程顺利学习。课程核心知识点地图如下: 课程每章核心知识点介绍如下: 第一章:介绍Qt环境搭建、QtCreator / VS2019的基本使用方法,Qt整体架构、Qt信号机制,Qt内存管理等知识。第二章:了解到很多学员对于Qt界面布局很不熟悉,将会详细介绍Qt设计器布局,以及如何C++代码手写布局,从常见的企业级项目入手,带领大家学会各种布局的实现,例如WPS、腾讯会议、优酷、迅雷等界面的实现;界面布局会了,这是企业项目开发的第一步,还有更重要的无边框窗口,如何设计一个合理的无边框窗口很重要,第三/四章:详细介绍如何实现一个无边框窗口,如何自定义标题栏,如何实现拖拽拉伸;第四章将会介绍如何自定义非标控件,优化Qt界面。第五章:介绍Qt web混合编程,一个商用项目,必然会涉及到web交互,这也是很多Qt开发者的弱项,这一章讲详细介绍C++ Qt web混合开发。第六章:既然是做企业级项目,必然需要和后台交互,http编程也是必要的,将详细介绍http编程,用户注册,登录,后台接口请求等知识;通过第五、六章的学习,将会是你的Qt开发技术更上一层楼。第七章:介绍Qt并发编程,耗时任务处理,进程调用等知识。第八、九章:讲解 Qt 比较重要的知识,图形视图结构,以及MVD模式;通过这两章的学习,大家会对图形视图有更好的了解。第十章:本章是独立章节,主要介绍Qt中一些特殊技巧,项目编译,dpi适配、多语言等知识。第十一章:是我们的企业级项目实战:实现一个视频会议客户端,本项目可以进行多人视频通话,直播,桌面分享等功能,本项目我会从零开始,进行项目搭建,功能调试,bug fixed, 带领大家做一个企业级项目。希望通过本课程的学习,大家的C++ Qt开发技术能有质的飞越,能找到自己心仪的工作。课程中如果讲的不对的地方,请大家指出,我及时修正,我也只是一个普通开发者,也不是所有的技术都会,尽我所能,把我所会的教给大家,让我们一起为Qt的发展,尽一份绵薄之力。 下面是本课程一些项目的截图: 1 可以滑动的设置界面         2 所有图形的绘制       3 视频播放器          4 高仿youku界面         5 视频会议         相信通过本课程的学习,大家有能力实现绝大部分客户端项目,从此用C++ Qt再也不会有难写的界面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值