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

转载自:万一的博客

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

时间: 2024-10-09 23:41:41

多线程编程(2)--从CreateThread说起的相关文章

多线程编程(4)--从CreateThread说起(倒数第三个参数)

转载自:万一的博客 function CreateThread( lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; {入口函数的参数} dwCreationFlags: DWORD; var lpThreadId; DWORD; ): THandle; stdcall; 线程入口函数的参数是一个无类型指针(Pointer),用它

多线程编程(3)--从CreateThread说起(倒数第二个参数)

转载自:万一的博客 function CreateThread( lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; {启动选项} var lpThreadId: DWORD ): THandle; stdcall; CreateThread的倒数第二个参数dwCreateFlasg

多线程编程基础知识

多线程编程基础知识 http://www.cnblogs.com/cy163/archive/2006/11/02/547428.html 当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的出现,对提高软件的并行性有着重要的意义.现在的大型应用软件无一不是多线程多任务处理,单线程的软件是不可想象的.因此掌握

多线程编程1

参考资料: http://blog.csdn.net/JXH_123/article/details/23450031                             秒杀多线程系列 http://www.baidu.com/index.php?tn=utf8kb_oem_dg&addresssearch=1#wd=C%2B%2B%E5%BE%AA%E7%8E%AF%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97&ie=utf-8&tn=utf8kb

C++多线程编程入门之经典实例

多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对多线程的理解程度从一个侧面反映了程序员的编程水平. 其实C++语言本身并没有提供多线程机制,但Windows系统为我们提供了相关API,我们可以使用它们来进行多线程编程.本文就以实例的形式讲解多线程编程的知识. 创建线程的API函数 C++代码 HANDLE CreateThread( __in   SEC_ATTRS SecurityAttributes, __in   ULONG StackSize,  

Windows下多线程编程(一)

前言 熟练掌握Windows下的多线程编程,能够让我们编写出更规范多线程代码,避免不要的异常.Windows下的多线程编程非常复杂,但是了解一些常用的特性,已经能够满足我们普通多线程对性能及其他要求. 进程与线程 1. 进程的概念 进程就是正在运行的程序.主要包括两部分: • 一个是操作系统用来管理进程的内核对象.内核对象也是系统用来存放关于进程的统计信息的地方. • 另一个是地址空间,它包含所有可执行模块或 D L L模块的代码和数据.它还包含动态内 2. 线程的概念 线程就是描述进程的一条执

apple平台下的objc的GCD,多线程编程就是优雅自然。

在apple的操作系统平台里,GCD使得多线程编程是那么的优雅自然.在传统的多线程编程中,首先要写线程处理循环:之后还有事件队列,消息队列:还要在线程循环中分离事件解释消息,分派处理:还要考虑线程间是否要同步:还要写许多有着可能费解的函数名的回调处理程序,注册回调程序,而且代码分散即使同一文件也不容易看出与哪些线程对应或者彼此间的是否有次序或并发的关系,不利于调试:另外还要考虑是否需要使用线程池,线程线使用何种模式等.在apple平台的objc中,只需要如下: A* a; dispatch_as

多线程编程示例(结合实例)

1.CreateThread与_beginthreadex #pragma once #include<cstdio> #include<Windows.h> #include<crtdbg.h> #include<process.h> //子线程函数 DWORD WINAPI ThreadFun1(LPVOID pM) { printf("子线程的线程ID号为:%d\nHello world!\n",GetCurrentThreadId

Windows多线程编程总结

Windows 多线程编程总结 keyword:多线程 线程同步 线程池 内核对象 1 内核对象 1 .1 内核对象的概念 内核对象是内核分配的一个内存块,这样的内存块是一个数据结构,表示内核对象的各种特征.而且仅仅能由内核来訪问.应用程序若须要訪问内核对象,须要通过操作系统提供的函数来进行,不能直接訪问内核对象( Windows 从安全性方面来考虑的). 内核对象通过 Create* 来创建,返回一个用于标识内核对象的句柄,这些句柄 (而不是内核对象)可在创建进程范围内使用,不可以被传递到其它