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

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

  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3. ExitThread(0); {此句即可退出当前程序, 但不建议这样使用}
  4. 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) 的定义:
--------------------------------------------------------------------------------

  1. PContext = ^TContext;
  2. _CONTEXT = record
  3. ContextFlags: DWORD;
  4. Dr0: DWORD;
  5. Dr1: DWORD;
  6. Dr2: DWORD;
  7. Dr3: DWORD;
  8. Dr6: DWORD;
  9. Dr7: DWORD;
  10. FloatSave: TFloatingSaveArea;
  11. SegGs: DWORD;
  12. SegFs: DWORD;
  13. SegEs: DWORD;
  14. SegDs: DWORD;
  15. Edi: DWORD;
  16. Esi: DWORD;
  17. Ebx: DWORD;
  18. Edx: DWORD;
  19. Ecx: DWORD;
  20. Eax: DWORD;
  21. Ebp: DWORD;
  22. Eip: DWORD;
  23. SegCs: DWORD;
  24. EFlags: DWORD;
  25. Esp: DWORD;
  26. SegSs: DWORD;
  27. end;

--------------------------------------------------------------------------------
 
CreateThread 的最后一个参数是 "线程的 ID";
 既然可以返回句柄, 为什么还要输出这个 ID? 现在我知道的是:
 1、线程的 ID 是唯一的; 而句柄可能不只一个, 譬如可以用 GetCurrentThread 获取一个伪句柄、可以用 DuplicateHandle 复制一个句柄等等.
 2、ID 比句柄更轻便.

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

转自:http://www.cnblogs.com/del/archive/2009/02/10/1387559.html

http://blog.csdn.net/rznice/article/details/8245788

多线程编程 CreateThread(解释了TContext)的更多相关文章

  1. CreateThread简单那多线程编程

    CreateThread简单那多线程编程 作者:vpoet mail:vpoet_sir@163.com 在进行多任务处理的时候我们往往会用到多线程技术,多线程理论上是多个线程同事处理不同的工作,但是 ...

  2. QThread多线程编程经典案例分析(三种方法,解释了为什么使用moveToThread的根本原因,即为了避免调用QThread::exec() )

    传统的图形界面应用程序都只有一个线程执行,并且一次执行一个操作.如果用户调用一个比较耗时的操作,就会冻结界面响应. 一个解决方法是按照事件处理的思路: 调用 Void QApplication::pr ...

  3. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  4. [转]Delphi多线程编程入门(二)——通过调用API实现多线程

    以下是一篇很值得看的关于Delphi多线程编程的文章,内容很全面,建议收藏. 一.入门 ㈠. function CreateThread(    lpThreadAttributes: Pointer ...

  5. VC++多线程编程

    一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX ...

  6. 多线程编程之二 ---MFC中的多线程开发

    下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...

  7. VC多线程编程

    一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX ...

  8. 《转》VC++多线程编程

    原地址:http://www.cnblogs.com/wxfasdic/archive/2010/09/23/1833522.html 留个纪念,不错的总结.十个例子清晰列举啦多线程编程的奥妙.  V ...

  9. VC++ 多线程编程,win32,MFC 例子(转)

    一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX ...

随机推荐

  1. GCJ 2008 Round 1A Minimum Scalar Product

    https://code.google.com/codejam/contest/32016/dashboard 题目大意: GCJ(google code jam)上的水题.下周二有比赛,来熟悉熟悉. ...

  2. C++ Tricks(一)—— 判断字符串 string 对象的所有字符都相等

    S == string(S.size(), S[0]);

  3. [Nuxt] Add CSS Libraries to Nuxt

    You can easily add CSS libraries to Nuxt using yarn or npm to install them, then simply adding them ...

  4. Latex表格制作记录

    Latex表格制作记录 主要功能 合并表格的行列 长表格的使用 makecell例程借鉴 效果图 参考代码 \documentclass{ctexart} \usepackage{indentfirs ...

  5. [RxJS] Hot Observable, by .share()

    .share() is an alias for .publish().refCount(). So if the source is not yet completed, no matter how ...

  6. 神奇校车 = topsage

    https://post.smzdm.com/p/6356/ 适合6岁至99岁的小盆友看的<The Magic School Bus> (神奇校车) http://club.topsage ...

  7. ios开发runtime学习五:KVC以及KVO,利用runtime实现字典转模型

    一:KVC和KVO的学习 #import "StatusItem.h" /* 1:总结:KVC赋值:1:setValuesForKeysWithDictionary实现原理:遍历字 ...

  8. 翻译 | Qt研发副总裁分享2018年工作计划

    原文作者:TuukkaTurunen,高级研发副总裁 翻译校审:Haipeng.Yulong和Ryan 引言:2018年,我们将继续完善Qt 5.9 LTS,现在我们正在为5月份发布Qt 5.11进行 ...

  9. VBA Code for Word Navigation Pane 【failed】 view-showheading-method-word

    https://msdn.microsoft.com/VBA/Word-VBA/articles/view-showheading-method-word View.ShowHeading Metho ...

  10. Kinect小小玩偶游戏----小小潜水员

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接: http://blog.csdn.net/cartzhang/article/details/44939887 作者:ca ...