Windows线程基础

简介:

线程由两部分组成:线程内核对象和线程栈。关于内核对象请看windows内核对象简介

线程内核对象,操作系统用线程内核对象来管理线程,操作系统还用它来存放统计信息。

线程栈,用于维护线程执行时所需的所有函数参数和局部变量,就是C#程序员常说的线程栈和托管堆中的线程栈。

我们知道进程是有惰性的,它的所有工作都是由线程完成的,而进程只是为线程提供场地,线程函数执行我们让它执行的任务,最终线程函数将终止运行并返回,线程将终止运行,线程的内存将被释放,线程内核对象的使用计数将减一,如果线程内核对象的使用计数减为0,线程内核对象将被销毁。

说了这么多,感觉有点虚,我们还是来看看创建线程的函数吧。

CreateThread(

    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    SIZE_T dwStackSize,

    LPTHREAD_START_ROUTINE lpStartAddress,

    LPVOID lpParameter,

    DWORD dwCreationFlags,

    PDWORD lpThreadId

);

lpThreadAttributes:用于设置线程的安全性,线程内核对象是否可以被进程的子进程所继承,详细了解我的这篇文章windows内核对象简介

dwStackSize:用于设置线程栈的大小,默认为1MB

lpStartAddress:线程所执行的函数的地址

lpParameter:线程函数的参数

dwCreationFlags:用于标识线程是否马上执行

lpThreadId:线程ID

创建线程。调用CreateThread时,系统会创建一个线程内核对象,这个内核对象由操作系统管理,当它的使用计数为0时,会被自动销毁。而当前进程的句柄表也会有一项用于纪录线程内核对象,表示对它的一个引用,同时系统会在进程的地址空间中分配一块内存共线程栈使用。新线程可以访问进程句柄表中的所有内核对象,内核对象由系统内核管理,而进程句柄表维护该进程所用到的内核对象的引用,而线程则通过句柄表中内核对象的地址引用内核对象。新线程还可以访问进程的所有内存以及进程中所有线程的栈,如子线程可以很方便的访问主线程的栈。还有一点需要说明的就是,线程内核对象创建完成之后,线程并不会马上执行,因为线程栈的内存分配和初始化时要时间的,等一切就绪后进程才会开始执行。

终止线程。最好让线程函数自动返回,而不应该强制终止线程函数,因为线程函数在返回前还要做些清理工作,如析构对象,回收内存,让操作系统正确释放线程栈使用的内存,如果强制终止关闭线程,可能这些工作就不能正确的执行,很可能就会出现内存泄露。

线程内幕。对CreateThread的调用产生一个线程内核对象,内核对象的使用计数为2,个人认为使用计数为2的原因是:当前进程对它的引用,还有就是保证在线程函数返回是内核对象不用马上自动销毁,因为当前函数返回时内核对象的使用计数肯定要减一,当减为0时内核对象将自动销毁。还要初始化内核对象的其他属性,并将内核对象设为未触发状态,使其随时可以被执行。等内核对象和线程栈内存一切就绪,系统就会将两个值写入新线程栈的最上端,一个是线程函数的参数,一个是线程函数的地址。

每个线程都有自己的一组CPU寄存器,即为线程的上下文。上下文反映了当前线程执行一次时线程CPU寄存器的状态。因为一个线程可能要经过多次的CPU轮询,才能执行完成,在每次CPU时间用完之前保存CPU寄存器的状态,好让下次轮询到达时继续执行。线程CPU寄存器全部都保存在一个CONTEXT结构中,而CONTEXT本身保存在线程内核对象中。指令指针寄存器和栈指针寄存器是线程上下文中两个重要的寄存器,线程始终在线程的上下文中运行,当线程的内核对象被初始化时,CONTEXT结构的堆栈指针寄存器被设为函数在线程栈中的地址,而指令指针寄存器被设为RtlUserThreadStart函数的地址,而函数RtlUserThreadStart则是线程开始的地方。

最后想说的是,建议用_beginthreadex代替CreateThread创建函数。

作者:陈太汉

博客:http://www.cnblogs.com/hlxs/



本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2012/12/16/2820992.html

目录
相关文章
|
5月前
|
调度 Windows
|
2月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
4月前
|
安全 API C++
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
147 0
|
Java 程序员 Windows
[笔记]Windows核心编程《十一》Windows线程池
[笔记]Windows核心编程《十一》Windows线程池
36666 4
[笔记]Windows核心编程《十一》Windows线程池
|
10月前
|
监控 安全 API
7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中`LyShark`一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以`监控进程线程`创建为例,在`Win10`系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原理是创建一个回调事件,当有进程或线程被创建或者注销时,系统会通过回调机制将该进程相关信息优先返回给我们自己的函数待处理结束后再转向系统层。
7.1 Windows驱动开发:内核监控进程与线程回调
|
10月前
|
监控 Windows
4.4 Windows驱动开发:内核监控进程与线程创建
当你需要在Windows操作系统中监控进程的启动和退出时,可以使用`PsSetCreateProcessNotifyRoutineEx`函数来创建一个`MyCreateProcessNotifyEx`回调函数,该回调函数将在每个进程的创建和退出时被调用。PsSetCreateProcessNotifyRoutineEx 用于在系统启动后向内核注册一个回调函数,以监视新进程的创建和退出,
4.4 Windows驱动开发:内核监控进程与线程创建
|
10月前
|
监控 安全 Windows
4.3 Windows驱动开发:监控进程与线程对象操作
在内核中,可以使用`ObRegisterCallbacks`这个内核回调函数来实现监控进程和线程对象操作。通过注册一个`OB_CALLBACK_REGISTRATION`回调结构体,可以指定所需的回调函数和回调的监控类型。这个回调结构体包含了回调函数和监控的对象类型,还有一个`Altitude`字段,用于指定回调函数的优先级。优先级越高的回调函数会先被调用,如果某个回调函数返回了一个非NULL值,后续的回调函数就不会被调用。当有进程或线程对象创建、删除、复制或重命名时,内核会调用注册的回调函数。回调函数可以访问被监控对象的信息,如句柄、进程ID等,并可以采取相应的操作,如打印日志、记录信息等。
4.3 Windows驱动开发:监控进程与线程对象操作
|
11月前
|
存储 安全 调度
4.2 Windows驱动开发:内核中进程线程与模块
内核进程线程和模块是操作系统内核中非常重要的概念。它们是操作系统的核心部分,用于管理系统资源和处理系统请求。在驱动安全开发中,理解内核进程线程和模块的概念对于编写安全的内核驱动程序至关重要。内核进程是在操作系统内核中运行的程序。每个进程都有一个唯一的进程标识符(PID),它用于在系统中唯一地标识该进程。在内核中,进程被表示为一个进程控制块(PCB),它包含有关进程的信息,如进程状态、优先级、内存使用情况等。枚举进程可以让我们获取当前系统中所有正在运行的进程的PID和其他有用的信息,以便我们可以监视和管理系统中的进程。
4.2 Windows驱动开发:内核中进程线程与模块
|
缓存 编译器 调度
[笔记]Windows核心编程《七》用户模式下的线程同步
[笔记]Windows核心编程《七》用户模式下的线程同步
|
编译器 索引 Windows
[笔记]Windows核心编程《二十一》线程本地存储器TLS
[笔记]Windows核心编程《二十一》线程本地存储器TLS
112 0

相关课程

更多