zoukankan      html  css  js  c++  java
  • 多线程编程 CreateThread(解释了TContext)

    [delphi] view plain copy
     
    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, 譬如下面代码:
    --------------------------------------------------------------------------------

    [delphi] view plain copy
     
    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) 的定义:
    --------------------------------------------------------------------------------

    [delphi] view plain copy
     
    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

  • 相关阅读:
    初探Java设计模式2:结构型模式(代理模式,适配器模式等)
    初探Java设计模式1:创建型模式(工厂,单例等)
    Java集合详解8:Java集合类细节精讲,细节决定成败
    Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同
    MySQL教程67-使用DISTINCT过滤重复数据
    MySQL教程66-数据表查询语句
    MySQL教程65-MySQL操作表中数据
    MySQL教程64-MySQL 流程控制函数
    MySQL教程63-MySQL 聚合函数
    MySQL教程62-MySQL日期和时间函数
  • 原文地址:https://www.cnblogs.com/findumars/p/8207146.html
Copyright © 2011-2022 走看看