【Window核心编程】学习笔记

1 简介

本书是讲解Windows操作系统内部机制的一本专著。作者从基本概念入手,全面系统地介绍了Windows底层实现机制、Windows应用程序的基本构件(包括进程、线程、内存管理、动态链接库、线程本地存储和Unicode)以及各类Windows API等,并列举了大量应用程序示例,精辟地分析了Windows编程的各个难点和要点,为掌握Windows编程技巧提供了一条有效的捷径。

2 重要主题

如何为32位和64位Windows系统构建和实现应用程序;
如何新建和处理进程与作业;
如何调度.管理、同步和销毁线程;
如何通过I/O完成端口执行同步和异步设备I/O操作;
如何使用虚拟内存、内存映射文件和堆之类的各种技术来分配内存;
如何处理默认调拨的线程栈物理存储;
如何为延迟加载、API拦截和进程注入构建DLL;
如何使用结构化异常处理、Windows错误恢复和应用程序重启等机制。

3 内核对象

本章内容:

  1. 何为内核对象
  2. 进程内核对象句柄表
  3. 跨进程边界共享内核对象

内核对象用于管理进程、线程和文件等诸多种类的大量资源

3.1 何为内核对象

每个内核对象都只是一个内存块,由操作系统内核分配,只能由操作系统内核访问(并非进程)。

3.1.1 使用引用计数

内核对象在被进程使用后,操作系统会将该内核对象计数器+1,所以操作系统知道当前有多少进程在使用一个特定的内核对象。
当计数为0,该内核对象被销毁。

3.1.2 其他对象

除了使用内核对象,应用程序还可能使用其他类型对象,比如菜单、窗口、鼠标光标、画刷等。这些都是用户对象或者GDI(Graphical Device Interface)对象,而非内核对象。

3.2 进程内核对象

一个进程在初始化时,系统将会为它分配一个句柄表(handle table),这个句柄表仅供内核对象使用,不适用于用户对象或者GDI对象。

3.2.1 创建一个内核对象

一个进程首次初始化时,其句柄表是空,当进程内的一个线程调用一个会创建内核对象的函数,内核将为这个对象分配一个并初始化一个内存块,然后内核扫描进程的句柄表,查找一个空白的纪录项。

3.2.2 关闭内核对象

如果忘记调用CloseHandle函数关闭内核对象,是否会发生对象泄漏吗?
不一定!
但是,在进程终止运行时,操作系统会确保此进程所有使用的资源都被释放!对于内核对象,操作系统执行的是以下操作:进程终止时,系统会自动扫描该进程的句柄表,如果这个表中有任何有效记录项,操作系统会为我们关闭这些对象句柄,当计数器减为0,内核对象被销毁。
可以使用任务管理器查看内核对象数量(Handles)

3.3 跨进程边界共享内核对象

不同进程的线程需要共享内核对象,可以使用多种方式完成:

  1. 文件映射对象,可以在同一台机器运行2个不同的进程之间共享数据块。
  2. 命名管道,网络中不同的进程可以相互发送数据库。
  3. 互斥量、信号量和事件允许不同的进程的线程同步执行。例如:当前应用程序可能需要在完成某个任务后,给另一个进程发送通知。

内核对象的句柄是每个进程相关的,若把内核对象句柄设计为相对于整个系统,一个进程就很容易的访问另一个进程正在使用的一个对象的句柄,从而对该进程造成严重破坏。另一方面由于安全性,内核对象是受安全性保护的,进程在试图操作一个对象之前,必须申请操纵他的权限。

3.3.1 使用对象句柄继承

只有进程之间有一个父子关系时,才可以使用对象句柄继承。
句柄可以继承,而对象本身不可以。复制句柄表后,系统会递增内核对象的使用计数。

3.3.3 为对象命名

Microsoft没有提供专门的机制来保证内核对象指定的名称是唯一的。

第三章小结

启动一个进程后,系统就会创建一个进程内核对象。

4 进程

一般将进程定义成一个正在运行的程序的一个实例,它由两部分组成。

  • 一个内核对象,操作系统用它来管理进程。内核对象也是系统保存进程统计信息的地方
  • 一个地址空间,其中包括所有可执行文件(.exe)或者DLL的模块的代码和数据。还包含动态内存分配,比如线程的堆栈。

每个进程至少一个线程来执行进程地址空间的代码。如果没有线程执行进程的地址空间包含的代码,系统此时就会自动销毁进程及其地址空间。

所有需要运行的线程OS会轮流为每个线程调度一些CPU时间,他们会采取循环(轮询或者轮流)的方式,为每个线程都分配时间片(称为“量”或者“量程”),从而营造一种所有线程都在运行的假象。

Window内核负责线程所有的管理和任务调度

系统创建进程会传递一个命令行给它,另外每个进程都有自己的环境变量。

4.1 CreateProcess函数

系统创建一个进程内核对象用于管理此进程(不是进程本身),为其创建一个虚拟地址空间,将可执行文件、DLL、代码、数据加载到进程的地址空间,然后为主线程创建一个线程内核对象,以便操作系统管理。

4.2 终止进程的方式
  1. 主函数返回,C++对象、线程栈、内核对象会正确释放
  2. 任意线程调用ExitProcesss(避免)
  3. 另一个进程调用TerminateProcess(避免)
  4. 自然死亡(机会没有)
4.3 进程通讯方式

管道、内存映射文件mmap、socket等等

5 线程

由两部分构成:

  1. 线程内核对象,操作系统用它管理线程、统计线程信息
  2. 一个线程栈,用于维护线程执行的所有参数和局部变量
5.1 和进程的对比

进程只是容器,线程才是真正执行单位

系统创建进程需要大梁系统资源,产生大量记录活动,使用大量内存,还需要加载exe、dll涉及到的文件资源。但是线程使用的系统资源很少,基本没有记录活动,以及很少的内存。

5.2 终止线程的方式
  1. 线程函数返回
  2. ExitThread杀死一个线程
  3. 其他进程或者线程调用TerminateThread终止线程,强行杀死线程,DLL是不可以正常收到消息,导致DLL加载的资源无法正常清理
  4. 进程的停止导致线程停止
5.3 线程堆栈

保存SP、IP其他CPU寄存器(CONTEXT上下文数据结构的数据),其他统计信息、引用计数信息、是否触发(内核对象)

5.4 线程调度、优先级
  • window之所以称之为抢占式多线程操作系统,是因为可以随时停止一个线程而运行下一个线程,只调度可调度的线程
  • 进程、线程的内核对象有一个记录挂起次数的计数,如果>1,表示正在挂起。比如线程正在初始化2
  • 系统检测是否存在饥饿线程,调用switchToThread调用
  • Sleep表示线程放弃剩余的CPU时间片
  • 一般一个线程会在同一个CPU调用,这样可以重用缓存
5.4.1 超线程技术

芯片划分了多个“逻辑”CPU,每个U都可以单独执行,但是共享CPU缓存

5.4.2 Context结构

CPU寄存器,Eip指令指针、Esp栈指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值