码迷,mamicode.com
首页 > 编程语言 > 详细

多线程编程(2)--从CreateThread说起

时间:2015-05-08 12:28:36      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

转载自:万一的博客

 

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);
begin
    ExitThread(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 = record
    ContextFlags: 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

 

多线程编程(2)--从CreateThread说起

标签:

原文地址:http://www.cnblogs.com/xumenger/p/4487068.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!