java 线程亲缘性_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的使用率。
java 线程亲缘性_Windows内核之线程的调度,优先级,亲缘性相关推荐
- 应用退出前不让线程切换_用户级线程和内核级线程,你分清楚了吗?
前天晚上有个伙伴私信我说在学进程和线程,问我有没有好的方法和学习教程,刚好我最近也在备相关的课. 班上不少学生学的还是很不错的.拿班上小白和小明的例子吧(艺名哈).小明接受能力很强,小白则稍差些. 关 ...
- 用户态和内核态:用户态线程和内核态线程有什么区别?
转载 文章来源于 拉钩教育 重学操作系统 林䭽 用户态和内核态:用户态线程和内核态线程有什么区别? 什么是用户态和内核态 Kernel 运行在超级权限模式(Supervisor Mode)下,所以拥有 ...
- 【Linux 线程】同一个进程中的线程共享哪些资源
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线 ...
- java 线程亲缘性_第7章 线程调度、优先级和亲缘性(1)
7.1线程的挂起和恢复 (1)线程挂起 ①创建时(如CreateProcess.CreateThread),传入CREATE_SUSPENDED标志 ②用SuspendThread挂起线程.这个函数可 ...
- 【Java 并发编程】线程池机制 ( 测试线程开销 | 启动线程分析 | 用户态 | 内核态 | 用户线程 | 内核线程 | 轻量级进程 )
文章目录 一.测试线程开销 1.正常测试 2.不创建线程 3.只创建不启动线程 4.只启动不等待执行完成 二.分析测试结果 1.启动线程分析 2.用户线程与内核线程 3.轻量级进程 4.验证 Java ...
- 5、Java并发性和多线程-相同线程
以下内容转自http://tutorials.jenkov.com/java-concurrency/same-threading.html(使用谷歌翻译): 相同线程(同一线程)是一种并发模型,其中 ...
- Java 面试题:数据结构 + 算法 +JVM+ 线程 +finalize+GC
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS 与 CS 的联系与区别 Coo ...
- 史上最全Java面试题:数据结构+算法+JVM+线程+finalize+GC
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
- 2022年史上最全Java面试题:数据结构+算法+JVM+线程+finalize+GC
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
最新文章
- Ubuntu常用快捷键
- linux多网卡bind发送数据,Linux系统多网卡绑定实战
- 今天的我家有12口人的即时通讯
- Python 告诉你疫情扩散有多可怕
- 1.1机器学习基础-python深度机器学习
- OpenGL基础13:第一个正方体
- Vue2.0进阶组件篇2 解析饿了么(spinner组件)
- 启用windows功能NetFx3时出错的离线解决方案
- 三宝小精灵机器人_“三宝”机器人
- PlatformIO开发STM8S003F3P6
- c++11 日期和时间工具-(std::chrono::steady_clock)(std::chrono::high_resolution_clock)
- 怎么更换电脑的默认浏览器?
- c语言 修正正弦曲线,[原创]正弦曲线
- 本机 ip 地址和本地ip地址的区别?
- 微众银行助力普惠金融实现高质量发展
- 重装电脑系统前,如何设置BIOS ?
- Phun一个有意思的程序
- UWB定位系统会存在定位误差吗?
- 产品思维考察之对象思维
- 西尔特280U 580U双芯片升级准3000U芯片 编程器 希尔特280u 580u 双芯片升级 3000u芯片 ,升级后稳定如同原厂 希尔特280u 580u都可以直接升级成3000u支持芯片翻
热门文章
- 用面向对象的思想做一款贪吃蛇小游戏
- 鲲鹏HCIP练习03答案
- 浪潮INSPUR等ERP程序多开方法
- Python绘制的爱心树与表白代码
- 【华为OD机试真题】Excel单元格数值统计(javapython)100%通过率 超详细代码注释 代码深度解读
- android+获取相册列表,android 获取相册列表的实现(二)
- ExoPlayer添加滤镜功能
- 用python画星空-python3的turtle画模仿3d星空、运动的恒星小宇宙
- Mindspore体验dcgan生成漫画头像
- mmse评估量表_简易智能精神状态检查量表(MMSE)