Windows 线程

来源:互联网 发布:虚拟交易平台源码 编辑:程序博客网 时间:2024/05/04 17:37
每个进程都至少需要一个线程,线程由两部分组成:
         一个是线程的内核对象,操作系统用它来对线程实施管理,内核对象也是系统用来存放线程统计信息的地方。
         另一个是线程堆栈,它用于维护线程在执行代码时需要的所有函数和局部变量。
进程是不活泼的,进程从来不执行任何东西,它只是线程的容器。
线程总是在某个进程环境中创建,而且它的整个寿命期在该进程中,这意味着线程在它的进程地址空间中执行代码,并且在进程地址空间中对数据进行操作。
        进程使用的系统资源比线程多得多,原因是它需要更多的地址空间,为进程创建一个虚拟地址空间需要许多系统资源。系统中药保留大量的记录,这要占用大量的内存。另外,由于.exe和.dll文件要加载到一个地址空间,因此也需要文件资源,而线程使用的系统资源要少得多。实际上,线程只需要一个内核对象和一个堆栈,保留的记录很少,因此需要很少的内存。
        由于线程需要的开销比进程少,因此始终都应该设法用增加线程来解决编程问题,而要避免创建新进程。但是这个建议不是一成不变的。许多程序设计用多个进程实现会更好些,需要权衡利弊。

        何时创建线程
        线程用于描述进程中的运行路径,每当进程被初始化时,系统就要创建一个主线程,该线程与C/C++运行期库的启动代码一道运行,启动代码则调用进入点函数(main,wmain,WinMain或wWinMain),并且继续运行直到进入点函数返回并且C/C++运行期库的启动代码调用ExitProcess为止。

        线程函数可以执行你想要它做的任何任务,最终,线程函数到达它的结尾处并且返回。这时,线程终止运行,该堆栈的内存被释放,同时,线程的内核对象的使用计数被递减,如果使用计数递减为0,线程的内核对象将被删除。与进程内核对象的情况相同,线程内核对象的寿命至少可以达到他们相关的线程那么长,不过该对象的寿命可以远远超过线程本身的寿命。

        线程函数的说明:
        1.主线程的进入点函数的名字必须为:main,wmain,WinMain,wWinMain与这些函数不同的是,线程函数可以使用任意名字,实际上,如果在应用程序中拥有多个线程函数,必须为它们赋予不同的名字,否则编译器/链接程序会认为你为单个函数创建了多个实现函数。
        2. 由于给你的主线程的进入点函数传递了字符串参数,因此可以使用ANSI/Unicode版本的进入点函数:main,wmain和WinMain,wWinMain。可以给线程函数传递单个参数。参数的含义由你定义,而不是操作系统定义。
        3.线程函数必须返回一个值,它将成为该线程的退出代码。这与C/C++运行期库关于让主线程的退出代码作为进程的退出代码原则相似。
        4.线程啊哈念书应该尽可能使用函数参数和局部变量。当使用静态变量和全局变量时,多个线程可以同时访问这些变量,这可能破坏变量的内容,然而参数和局部变量是在线程堆栈中创建的,因此不太可能被另一个线程破坏。

    CreateThread函数
    HANDLE CreateThread(
        PSECURITY_ATTRIBUTES psa,                                 //线程内核对象的默认安全属性,可以传递NULL。
        DWORD cbStack,                                                    //用于设定线程可以将多少地址空间用于自己的堆栈
        PTHREAD_START_ROUTINE pfnStartAddr,           //指明想要新线程执行的线程函数的地址
        PVOID pvParam,                                                        //传递给线程函数
        DWORD fdwCreate,                                                //可以设定用于控制创建线程的其他标志0,表示立即进行调度,                                                    CREATE_SUSPENDED表示系统可以创建线程并对它进行初始化,但是要暂停该线程的运行,这样它就无法调度。
        PDWORD pdwThreadID);                                     //使用这个地址来存放系统分配给新线程的ID                                 
        当CreateThread被调用时,系统创建一个线程内核对象,该线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。可以将线程内核对象视为由关于线程的统计信息组成的一个小型数据结构。这与进程和进程内核对象之间的关系是相同。
        系统从进程的地址空间中分配内存,供线程的堆栈使用。新线程运行的进程环境与创建线程的环境相同,因此,新线程可以访问进程的内核对象所有的句柄,进程中的所有内存和这个相同的进程中所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易的相互通信。

       注意: CreateThread函数时用来创建线程的Windows函数,不过如果你正在编写C/C++代码,绝不应该调用CreateThread。相反,使用visual C++运行期库函数_beginthreadex。如果不是使用Microsoft的VisualC++编译器,你的编译器供应商有它自己的CreateThread替代函数。
         
        终止线程的运行
          若要终止线程的运行,可以使用下面的方法:
        1.线程函数返回(The best method)
        2.通过调用ExitThread函数,线程将自行撤销(最好不要使用这种方法)
        3.同一个进程或者另一个进程的线程调用TerminateThread函数(应该避免使用)
        4.包含线程的进程终止运行
        
           线程函数返回:
            如果线程函数能够返回,就可以确保下列事项的实现,
            1.在线程函数中所创建的所有C++对象均将通过它们的撤销函数正确的撤销,
            2.操作系统将正确的释放线程堆栈使用的内存,
            3.系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
            4.系统将递减线程内核对象的使用计数。
        ExitThread函数:
        可以让线程调用ExitThread函数,以便强制线程终止运行,VOID ExitThread(DWORD dwExitCode)
        该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源,但是C++资源将不被撤销。
             如果编写C/C++代码,应该使用VisualC++运行期库函数_endthreadex。

        TerminateThread函数
        BOOL TerminateThread(
                HANDLE hThread,
                DWORD   dwExitCode);
        与ExitThread不同,ExitThread总是撤销调用的线程,而TerminateThread能够撤销任何线程,hThread参数用于标识被终止运行的线程的句柄,当线程终止运行时,它的退出代码成为你作为dwExitCode参数传递的值,同时,线程的内核对象的使用计数也被递减。
            注意:TerminateThread 函数时异步运行的函数,也就是说,他告诉系统你想要线程终止运行,但是当函数返回时,不能保证线程被撤销。如果需要确切地知道该线程已经终止运行,必须调用WaitForSingleObject或者类似的函数,传递线程的句柄。


        线程终止运行时发生的操作
        1.线程拥有的所有用户对象均被释放,在Windows中,大多数对象是由包含创建这些对象的线程所拥有的,但是一个线程拥有两个用户对象,即窗口和挂钩。当线程终止运行时,系统会自动撤销任何窗口,并且卸载线程创建的或安装的任何挂钩,其他对象只有在拥有线程的进程终止运行时才被撤销。
        2.线程的退出代码从STILL_ACTIVE改为传递给ExitThread或TerminateThread的代码。
        3.线程内核对象的状态变为已通知。
        4.如果线程是进程中最后一个活动线程,系统也将进程视为已经终止运行。
        5.线程内核对象的使用计数递减1。
    当一个线程终止运行时,与它相关联的线程内核对象的所有未结束的引用关闭之前,该内核对象不会自动被释放。
    一旦线程不再运行,系统中就没有别的线程能够处理该线程的句柄。然而别的线程可以调用GetExitCodeThread来检查由hThread标识的线程是否已经终止运行,如果已经终止运行,则确定它的退出代码。
        
        BOOL GetExitCodeThread(
            HANDLE hThread,
            PDWORD pdwExitCode);
        退出代码的值在pdwExitCode指向DWORD中返回。如果调用GetExitCodeThread时线程尚未终止,该函数就用STILL_ACTIVE标识符填入DWORD。
0 0
原创粉丝点击