探索Windows:Windows内存结构体系
让我们与星光探索者一起,探索Windows吧!
探索Windows:同步设备IO与异步设备IO
让我们与星光探索者一起,探索Windows吧!
线程是我们最好的工具,可以用来对工作进行划分。然而当线程发出一个异步设备I/O请求时,他被临时挂起,知道设备完成I/O请求为止。此类挂起会损害性能。为了不让线程闲下来,我们需要让各个线程就他们正在执行的操作相互通信。Microsoft开发出了一个非常好的机制进行这类通信–I/O完成端口(I/O completion port)他可以帮助我们创建高性能而且伸缩性好的应用程序。通过使用I/O完成端口,我们可以让线程在读取设备和写入设备时不必等待设备的响应,从而显著提高吞吐量。
打开和关闭设备以下为常见的可称为设备的东西,一般设备使用CreateFile打开,CloseHandle关闭。这些函数都返回一个标识设备的句柄,我们可以将句柄传给许多函数与设备进行通信,如调用SetCommConfig设置串口的波特率,SetMailslotInfo在等待读取数据时,设置超时值。如果我们想知道设备的类型,可通过调用GetFileType函数获得
设备
常见用途
文件
永久储存任何数据
目录 ...
探索Windows:线程同步
让我们与星光探索者一起,探索Windows吧!
通常,线程之间需要进行通信,而通信时很可能就会导致数据混乱的现象。就好比一个人正在读书时,另一个人正在修改书中文字。这样书的内容将乱七八糟。对于多个线程同时访问一个共享资源,或一个线程需要通知其他线程某任务已经完成时,需要用到线程同步。Microsoft已提供了很多基础设施,使得线程同步很容易。
用户模式下的线程同步我们可以有多种方式实现线程同步
使用原子锁线程同步的一大部分与原子访问有关(atomic access)有关。看如下代码
1234567891011121314151617181920long g_x = 0;DWORD WINAPI Work1(PVOID){ for (int i = 0; i < 100; ++i) { g_x++; } return 0;}DWORD WINAPI Work2(PVOID){ for (int i = 0; i < 100; ++i) { g_x++; ...
探索Windows:探索Windows内核对象线程
让我们与星光探索者一起,探索Windows吧!
线程的创建时机之前的探索过程中,我们知道,每个进程至少都有一个线程。进程有两个组成部分:一个进程内核对象和一个地址空间。类似地,线程也有两个组成成分
线程内核对象:操作系统用它管理线程
线程栈:用于维护线程执行时所需的所有函数参数和局部变量
进程是有惰性的,进程从来不执行任何东西,他只是一个线程的容器。线程共享同一个地址空间,执行同样代码,处理相同数据,此外,这些线程还共享对象句柄。
因此,进程相对于线程使用的系统资源更多。原因在于为一个进程创建一个虚拟的地址空间需要大量系统资源,系统发生大量记录活动,占用大量内存。线程几乎不涉及记录活动,所以不需要占用多少内存。
每个计算机都有强大的资源CPU。让CPU闲着是没有任何道理的(假设不考虑省电和散热等问题)。为了让CPU保持“忙碌”,我们可以让他执行多个任务。下面有多个案例:
Windows Indexing Services(Windows索引服务)创建了一个低优先级的线程,此线程定期醒来,并对硬盘上的特定资源的文件内容进行索引,这极大改进了性能。
只要暂停输入,Microso ...
探索Windows:探索Windows内核对象作业
让我们与星光探索者一起,探索Windows吧!
内核对象作业Job在Visual Studio中,我们有时候想在编译文件中途终止编译,调试程序中途终止调试,Visual Studio是怎么做的呢?虽然这是一个简单而常见的问题,但windows没有维护线程之间的父子关系,解决起来非常难。
Windows提供了一个作业(job)内核对象,它允许你将进程组合在一起并创建一个”沙箱”来限制进程能够做什么.最好将作业对象想象成一个进程容器.但是,即使作业中只包含一个进程,也是非常有用的,因为这样可以对进程施加平时不能施加的限制.点我查看微软官方对于作业对象的介绍
下面的程序代码,将尝试将一个进程放到一个作业中
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include <windows.h>#include <stdio.h>#incl ...
探索Windows:探索Windows内核对象进程 (2)
让我们与星光探索者一起,探索Windows吧!
再探CreateProcess函数我们用CreateProcess函数创建一个进程,CreateProcess函数的原型如下
1234567891011121314BOOL CreateProcess( LPCTSTR lpApplicationName, // 应用程序名称 LPTSTR lpCommandLine, // 命令行参数 LPSECURITY_ATTRIBUTES lpProcessAttributes, // 默认进程的安全属性,可传NULL LPSECURITY_ATTRIBUTES lpThreadAttributes, // 默认进程的安全属性,可传NULL BOOL bInheritHandles, // 当前进程内核对象能否被子进程继承 DWORD dwCreationFlags, // 创建进程 ...
探索Windows:探索Windows内核对象进程
让我们与星光探索者一起,探索Windows吧!
再次探索Windows应用程序进程由以下两部分构成:
一个内核对象,操作系统用于管理进程
一个地址空间,包含所有可执行文件或DLL模块的代码和数据,以及动态内存分配。
进程是有惰性的,进程要做的事情,必须让一个线程在他的上下文中运行,该线程负责执行进程空间包含的代码。一个进程可以有多个线程,所有线程都在进程的地址空间“同时”执行代码。为此,每个线程都有他自己的一组CPU寄存器和它自己的堆栈,每个进程至少有一个线程执行进程地址空间包含的代码。当系统创建一个进程的时候,会自动为进程创建第一个线程,这即为主线程(main thread)。 如果没有线程要执行进程地址空间包含的代码,进程失去了继续存在的理由,这是系统就会自动销毁进程及其地址空间。
对于所有要运行的线程,操作系统会轮流给每个线程调度一些CPU时间,采用循环(round-robin,轮询或轮流)方式,为每个线程分配时间片(quantum,称为“量”或“量程”),从而营造出所有线程都在同时运行的假象。 如果计算机配备了多个CPU,操作系统会采用更复杂的算法为线程分配CPU时间, ...
探索Windows:Windows内核对象初步探讨
让我们与星光探索者一起,探索Windows吧!
Windows内核对象初步认识Windows中有很多像访问令牌(access token)对象、事件(event)对象、进程(process)对象、线程(thread)对象、文件(file)对象、文件映射(filemapping)、可等待计时器(waitable timer)对象等等这样的对象,我们称之为Windows内核对象。内核对象是系统地址空间中的一个内存块,由系统创建并维护,这个内存对象是一个数据结构,维护着与对象相关的信息。微软提供了一些可以操作内核对象的API,可以使我们以适当的方式操作内核对象。关于内核对象的参考内容。
内核对象的所有者是操作系统,而非进程。如果我们的进程创建了一个内核对象,我们的进程终止之后,内核对象不一定被销毁, 因为可能别的进程使用我们的内核对象(如在下文中提到子进程继承父进程内核对象句柄,此时父进程终止之后,内核对象不一定被销毁)。
操作系统当然知道有多少进程使用同一个内核对象,因为每个内核对象都有一个叫引用计数(usage count)的共有数据成员。 初次创建一个内核对象时,他的引用计数为1,当一 ...
探索Windows:Windows错误处理和字符串处理
让我们与星光探索者一起,探索Windows吧!
Windows错误处理在Windows API 调用时,Windows会验证我们传入的参数是否有效,然后才会执行任务。下表为Windows大部分API函数返回值的意义。
返回值类型
返回值意义
VOID
此函数不会调用失败,但只有极少数 Windows函数返回值类型为 VOID
BOOL
如果函数失败返回0,否则返回一个非零值。因此在判断API是否调用成功时,不应该判断返回值是否为 TRUE,而是判读是否为FALSE
HANDLE
如果函数调用失败,返回NULL或INVALID_HANDLE_VALUE,这取决于文档说明。否则返回一个可以操纵的对象
PVOID
失败返回NULL,否则返回一块内存地址
Windows API是通过返回值来表明函数的调用成功情况的。当Windows返回错误代码时,我们就可以知道为什么函数调用失败。当Widnows检测到错误时,他会使用线程本地存储区(thread-local storage)的机制将发出调用的线程(calling thread)关联在一起,这种机制使得我们在不同的线 ...
C++面向对象知识点总结
本文记录了C++面向对象的相关知识点。
面向对象初识何为面向对象面向过程(Procedure Oriented):在解决一个问题时,将过程拆分为解决事情的步骤,然后按一定的顺序执行这些步骤,然后解决问题。优点是性能相对面向对象高,因为对象需要构建,开销比较大。缺点是不易维护。
面向对象(Object Oriented):在解决一个问题时,面向对象会将事物抽象成对象的概念,看此问题有哪些对象,这些对象会有什么行为,什么属性,让每个对象执行自己的行为,然后解决问题。优点是易维护易复用易拓展,缺点是性能比面向过程低,但也不会非常低。对象的行为和属性称为对象的成员。
什么是对象,例如人,手机,是对象什么是行为,例如走路,跑步,转身什么是属性,例如人的年龄,手机的电量,人的身高
具有相同行为,属性的对象组成的集合叫做类。
参考案例:用圆规画圆面向过程:拿出圆规,修改圆规半径,旋转圆规,结束面向对象:圆规创建,圆规.调整自身大小行为,圆规.旋转行为,结束。
参考案例:洗衣服面向过程:把衣服放入洗衣机,设置洗衣时间,设置洗衣模式,开启洗衣机,结束面向对象:构造圆规,洗衣机.放入衣服, 洗衣机. ...
星光心灵 - 如何安慰他人
Life is like a wave, which will go up and down. We cannot avoid suffering. Thus, we all need others’ comfort. The following informations show the useful tips to comfort people.
人生就像波浪,会起起落落。我们无法避免痛苦。因此,我们都需要别人的安慰。以下信息显示了安慰人们的有用技巧。
Better not to…
最好不要…
Tell him or her that your situation is worse 跟他比惨When someone turns to you, it is clear he or she wants your comfort. Telling “Mine is worse” always means “I can afford the worse situation than yours. So why can’t you?”. Although our thoughts are ...
星光心灵 - 倾听是否重要
We all like to tell our thoughts to others when in an informal conversation. As you can see, sometimes someone has not ended up talking, others can’t help cutting in. Who masters speaking is welcomed, but a man who is good at listening is also attractive.
我们都喜欢在非正式对话中向他人讲述我们的想法。如你所见,有时有人没有结束说话,其他人会忍不住插话。谁精通说话是受欢迎的,但善于倾听的人也很有吸引力。
In he occasion when a man listens to you, you will feel like you are respected, trusted, not ignored. It is the man who understands you! He does still listen to your wor ...
探索Windows:探索绘图编程和对话框
让我们与星光探索者一起,探索Windows吧!
探索绘图编程GDI,Graphic Device Interface,Windows提供了大量API供我们绘制各种各样的图形。
Windows每个窗口都是绘制出来的,当窗口需要绘制的时候,产生WM_PAINT消息,进而我们可以绘制窗口。
HDC,即为设备上下文句柄,DC是设备windows特有的一个概念,我们需要使用他来绘图。
下面是简单的绘图代码:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879#define _CRT_SECURE_NO_WARNINGS#include "MyWindowApplication/resource.h"#include <windows.h>#pragma comment(lib, "user32.lib" ...
探索Windows:使用计时器和菜单,图标,光标等资源文件
让我们与星光探索者一起,探索Windows吧!
使用计时器计时器是Windows的一种资源。定时器每隔一段时间,会产生WM_TIMER消息 。WM_TIMER附带的两个信息wParam, lParam分别是计时器的id, 计时器到点的处理函数。定时器的精度是毫秒,但是准确度不好。也就是说如果设置间隔1000ms,不一定会在1000ms后刚好产生消息。但是误差不会这么大,最多也就几毫秒。
要使用计时器,需要用SetTimer函数创建定时器。SetTimer的定义如下:
123456UINT_PTR SetTimer( HWND hWnd, // 计时器关联的窗口句柄 UINT_PTR nIDEvent, // 计时器的ID,自己随意定,但不能为0 UINT uElapse, // 计时器的间隔,单位毫秒 TIMERPROC lpTimerFunc // 计时器到点的处理函数);
这个函数返回创建的计时器ID,如果创建失败了返回0。如果lpTimerFunc传的是NULL,计时器的时间到了,就将发送WM_TIMER消息通 ...
探索Windows:处理常用的消息和自定义消息
让我们与星光探索者一起,探索Windows吧!
下发假设您自己的窗口类的窗口过程函数均为WndProc,且您正确的按流程写了自定义的窗口程序
下方均是提供的一种处理方式的代码,并不是必须要这么做。
处理WM_CLOSE消息WM_CLOSE消息在窗口即将终止时产生。
此消息附带的两个信息
wParam 未使用
lParam 未使用
处理窗口过程函数一个例子如下:
12345678910111213LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ switch (uMsg) { case WM_CLOSE: // 应调用此函数,这样会发送WM_QUIT消息 // 使GetMessage返回0,这样进程才会正确退出 PostQuitMessage(0); // 不要让默认处理函数处理,否则可能会出错 return 0; } return DefWi ...