function CreateThread(lpThreadAttributes: Pointer;           {安全设置}dwStackSize: DWORD;                    {堆栈大小}lpStartAddress: TFNThreadStartRoutine; {入口函数}lpParameter: Pointer;                  {函数参数}dwCreationFlags: DWORD;                {启动选项}var lpThreadId: DWORD                  {输出线程 ID }
): THandle; stdcall;                     {返回线程句柄}


在 Windows 上建立一个线程, 离不开 CreateThread 函数;
TThread.Create 就是先调用了 BeginThread (Delphi 自定义的), BeginThread 又调用的 CreateThread.
既然有建立, 就该有释放, CreateThread 对应的释放函数是: ExitThread, 譬如下面代码:


procedure TForm1.Button1Click(Sender: TObject);
beginExitThread(0); {此句即可退出当前程序, 但不建议这样使用}
end;


代码注释:
当前程序是一个进程, 进程只是一个工作环境, 线程是工作者;
每个进程都会有一个启动线程(或叫主线程), 也就是说: 我们之前大量的编码都是写给这个主线程的;
上面的 ExitThread(0); 就是退出这个主线程;
系统不允许一个没有线程的进程存在, 所以程序就退出了.
另外: ExitThread 函数的参数是一个退出码, 这个退出码是给之后的其他函数用的, 这里随便给个无符号整数即可.

或许你会说: 这个 ExitThread 挺好用的; 其实不管是用 API 还是用 TThread 类写多线程, 我们很少用到它; 因为:

1、假如直接使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;

2、用 TThread 类建立的线程又绝不能使用 ExitThread 退出; 因为使用 TThread 建立线程时会同时分配更多资源(譬如你自定义的成员、还有它的祖先类(TObject)分配的资源等等), 如果用 ExitThread 给草草退出了, 这些资源将得不到释放而导致内存泄露. 尽管 Delphi 提供了 EndThread(其内部调用 ExitThread), 这也不需要我们手动操作(假如非要手动操作也是件很麻烦的事情, 因为很多时候你不知道线程是什么时候执行完毕的).



除了 CreateThread, 还有一个 CreateRemoteThread, 可在其他进程中建立线程, 这不应该是现在学习的重点;
现在先集中精力把 CreateThread 的参数搞彻底.

倒着来吧, 先谈谈 CreateThread 将要返回的 “线程句柄”.

“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;

有句柄的对象一般都是系统级别的对象(或叫内核对象); 之所以给我们的是句柄而不是指针, 目的只有一个: “安全”;

貌似通过句柄能做很多事情, 但一般把句柄提交到某个函数(一般是系统函数)后, 我们也就到此为止很难了解更多了; 事实上是系统并不相信我们.

不管是指针还是句柄, 都不过是内存中的一小块数据(一般用结构描述), 微软并没有公开句柄的结构细节, 猜一下它应该包括:
真实的指针地址、访问权限设置、引用计数等等.

既然 CreateThread 可以返回一个句柄, 说明线程属于 “内核对象”.

实际上不管线程属于哪个进程, 它们在系统的怀抱中是平等的; 在优先级(后面详谈)相同的情况下, 系统会在相同的时间间隔内来运行一下每个线程, 不过这个间隔很小很小, 以至于让我们误以为程序是在不间断地运行.

这时你应该有一个疑问: 系统在去执行其他线程的时候, 是怎么记住前一个线程的数据状态的?

有这样一个结构 TContext, 它基本上是一个 CPU 寄存器的集合, 线程是数据就是通过这个结构切换的, 我们也可以通过 GetThreadContext 函数读取寄存器看看.

附上这个结构 TContext(或叫: CONTEXT、_CONTEXT) 的定义:


PContext = ^TContext;
_CONTEXT = recordContextFlags: DWORD;Dr0: DWORD;Dr1: DWORD;Dr2: DWORD;Dr3: DWORD;Dr6: DWORD;Dr7: DWORD;FloatSave: TFloatingSaveArea;SegGs: DWORD;SegFs: DWORD;SegEs: DWORD;SegDs: DWORD;Edi: DWORD;Esi: DWORD;Ebx: DWORD;Edx: DWORD;Ecx: DWORD;Eax: DWORD;Ebp: DWORD;Eip: DWORD;SegCs: DWORD;EFlags: DWORD;Esp: DWORD;SegSs: DWORD;
end;


CreateThread 的最后一个参数是 “线程的 ID”;

既然可以返回句柄, 为什么还要输出这个 ID? 现在我知道的是:

1、线程的 ID 是唯一的; 而句柄可能不只一个, 譬如可以用 GetCurrentThread 获取一个伪句柄、可以用 DuplicateHandle 复制一个句柄等等.

2、ID 比句柄更轻便.

在主线程中 GetCurrentThreadId、MainThreadID、MainInstance 获取的都是主线程的 ID.


啰哩啰嗦一大些, 才说了 CreateThread 一个参数, 下篇继续.

线程的学习还在入门中, 把我的理解写在这, 最期望的收获是得到指正.


C++ CreateThread详解相关推荐

  1. CreateThread用法详解

    CreateThread用法详解 今天我给大家讲一讲C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面 ...

  2. java基础(十三)-----详解内部类——Java高级开发必须懂的

    java基础(十三)-----详解内部类--Java高级开发必须懂的 目录 为什么要使用内部类 内部类基础 静态内部类 成员内部类 成员内部类的对象创建 继承成员内部类 局部内部类 推荐博客 匿名内部 ...

  3. 9、Windows驱动开发技术详解笔记(5) 基本语法回顾

    5.在驱动中获取系统时间 1)获取启动毫秒数 在ring3 我们可以通过一个GetTickCount 函数来获得自系统启动开始的毫秒数,在ring0也有一个与之对应的KeQueryTickCount ...

  4. 手把手教你玩转SOCKET模型:完成端口(Completion Port)详解

    这篇文档我非常详细并且图文并茂的介绍了关于网络编程模型中完成端口的方方面面的信息,从API的用法到使用的步骤,从完成端口的实现机理到实际使用的注意事项,都有所涉及,并且为了让朋友们更直观的体会完成端口 ...

  5. 完成端口(Completion Port)详解----- By PiggyXP(小猪)

    本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中--酝酿了两年之后,终于决定开始动笔了,但愿还不算晚-.. 这篇文档我非常详细并且图文并 ...

  6. Socket模型详解

    Socket模型详解 两种I/O模式 一.选择模型 二.异步选择 三.事件选择 四.重叠I/O模型 五.完成端口模型 五种I/O模型的比较 两种I/O模式 1. 两种I/O模式 阻塞模式:执行I/O操 ...

  7. linux下多线程的创建与等待详解 【转载】

    linux下多线程的创建与等待详解 http://blog.chinaunix.net/uid-23842323-id-2656572.html 所有线程都有一个线程号,也就是Thread ID.其类 ...

  8. 完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三 1-转

    完成端口(Completion Port)详解 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中--酝酿了两年之后,终于决定开始动笔了, ...

  9. 手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解

    2019独角兽企业重金招聘Python工程师标准>>> 前 言 本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿之中--酝 ...

最新文章

  1. 中小型网络的域环境搭建--第五季(搭建FTP服务器)
  2. opencv for arm
  3. python网页优化公司_使用python优化scipy.optimize.minimize公司
  4. pyqt5讲解2:QPushButton,QRadioButton,QCheckBox
  5. ActiveMQ的消息存储(八)
  6. 关于 php mysql pdo cannot find driver 解决方案
  7. 我有机器人合体成一个大力神_史上最菜大力神(三)——SS加强级高塔
  8. 整理了二个基本的css库(高手请绕道)
  9. 大流量场景下如何云淡风轻地进行线上发布?
  10. ppt学习02——字体
  11. (附源码)计算机毕业设计SSM保险客户管理系统
  12. Java户籍管理系统的设计与实现
  13. VC/MFC 编程经验
  14. beeline客户端连接hiveserver2问题
  15. target=“_blank“有啥安全性问题?如何防范?
  16. 【多态】【虚表指针与虚表】【多继承中的多态】
  17. php 圆柱体,认识圆柱体a href=http://ruiwen.com/friend/list.php(教师中心专稿)/a
  18. 战略制定4大关键要点
  19. 一位全加器及四位全加器————FPGA
  20. java寂静岭 攻略,《寂静岭:起源》全剧情攻略

热门文章

  1. android root注意事项,菜鸟获取手机root权限前不得不看的几点注意事项
  2. “设备回收”功能模块记录
  3. vue3警告: [Vue warn]: Component inside renders non-element root node that cannot be animat
  4. 用计算机画画教学设计,黔教版信息技术四年级上册第2课《用计算机的“笔”来画画》教案1.doc...
  5. 逻辑回归中的损失函数
  6. Bucket Join:分桶Join
  7. python之wheel 包命名规则、abi 兼容和安装
  8. 【Matlab】代码自动写word文档画图,修改figure尺寸的方法
  9. c#语言swith的用法,C# switch 语句 | Microsoft Docs
  10. python+selenium进行web自动化测试