• win32多线程程序设计学习笔记(第一、二章)


    第一章

    这一章主要介绍了为什么要引入多线程,以及多线程技术在windows系统中的发展历史。

    内存大致可以分为3中类型,分别是code,data和stack。code是程序的可执行部分,一定是只读性质。只是cpu唯一允许执行的内存 。data是程序中的所有变量(不包括函数中的局部变量),可分为全局和静态变量两种。stack是你调用函数时所用的堆栈空间,其中有局部变量。每个线程产生时配有一个堆栈。

    第二章 线程的第一次接触

    (1) 产生一个线程

    HANDLE CreateThread(
      LPSECURITY_ATTRIBUTES lpThreadAttributes, 
    //施行于这一线程的security属性
      DWORD dwStackSize,                        //新线程有自己的堆栈,0表示缺省大小1MB
      LPTHREAD_START_ROUTINE lpStartAddress,    //新线程运行的函数指针
      LPVOID lpParameter,                       //上一个函数的参数
      DWORD dwCreationFlags,                    //允许产生那个一个暂时挂起的线程,默认立即运行
      LPDWORD lpThreadID               //新线程的ID会被回传到这里
    BOOL CloseHandle(
      HANDLE hObject       
    //代表一个已打开对象之handle
    );

    )
    返回值:如果CreateThread()成功,传回一个handle,代表新线程。否则传回一个FALSE。如果失败,可以调用GetLastError()获知原因。

    其中,新线程的运行函数的原型是:

    DWORD WINAPI ThreadProc(
      [
    in]                 LPVOID lpParameter
    );

    (2)核心对象

    CreateThread传回2个值,用以识别一个新的线程。第一个是HANDLE,就是他的返回值。大部分与线程有关的API函数都需要它。第二个是有lpThreadID带回来的线程ID,线程ID是一个全局变量,可以唯一地表示系统中任一进程的某个线程。

     wind32核心对象有进程(processes),线程(threads),文件(files),事件(events),信号量(semaphores),互斥器(mutexes)和管道(pipes).

    GDI对象和核心对象的不同。GDI对象有单一的拥有者,不是进程就是线程;核心对象 可以有一个以上的拥有者,甚至可以跨进程。

    3)CloseHandle的重要性

    BOOL CloseHandle(
      HANDLE  hObject  
    //代表一个已打开对象的handle
    );

    返回值:如果成功返回TRUE。失败返回FALSE。

    如果一个进程没有在结束之前针对它所打开的核心对象调用CloseHandle,操作系统会自动把那些对象的引用计数下降一。如果一个进程常常产生“worker”线程二不管他,那么这个进程可能最终有数百个开启的“线程核心对象”留给系统区清理。这样的资源泄漏会对效率产生负面影响。

     不可以依赖“因线程的结束而清理所有被这一线程产生的核心对象”。许多对象,是被进程拥有,而非被线程拥有。在进程结束之前不能够清理他们。

     当你调用CloseHandle应给予它一个线程 handle时,只不过是表示,你希望自己和次核心对象不再有任何瓜葛。CloseHandle唯一做的事情就是把引用计数减一。如果该值编程0,对象会自动被操作系统摧毁。

    ”线程核心对象“ 引用到的那个线程也会令核心对象开启。因此,线程对象的默认引用计数是2.

    (4)线程结束代吗

     线程的结束代码表示了线程的状态,可以调用GetExitCodeThread。

    BOOL  GetExitCodeThread(
        HANDLE  hThread,            
    //由CreateThread传回的线程handle
        LPDWORD lpExitCode          //指向一个DWORD,用以接受结束代码(exit code)
    );

    返回值:如果成功,GetExitCodeThread传回TRUE,否则传回FALSE。如果线程已结束,那么线程的结束代码会被放在lpExitCode参数中带回来。如果未结束,lpExitCode带回来的是STILL_ACTIVE.

    (5)强制结束一个线程

    ExitThread可以强制结束一个线程

    VOID ExitThread(
      DWORD  dwExitCode          
    //指定此线程之结束代码
    );

    程序启动后就执行的那个线程称为主线程(primary thread)。主线程有2个特点。第一,他必须负责GUI程序中的主消息循环。第二,这一线程的结束会使得程序中的所有线程都被强迫结束,程序也因此结束。其他线程没有机会做清理工作

     (6)微软多线程模型

     win32说明文件强调线程分为GUI线程和worker线程。GUI线程负责建造 窗口以及处理主消息循环。worker负责执行纯粹运算工作,如重新计算等,他们会导致主线程的消息队列失去反映。一般而言,GDI线程绝不会去做那些不能够马上完成的工作。

    GUI线程的定义是:拥有消息队列的线程。任何一个特定窗口的消息总是被产生这一窗口的线程抓到并处理。所有对此窗口的改变也都应该由该线程完成。

    如果worker线程也产生了一个窗口,那么就会有一个消息队列也随之产生并且附加到此线程上。于是worker线程就变为一个GUI线程 。不过,worker线程不能产生窗口,对话框,消息框会其他与UI有关的东西。

     如果一个worker线程需要输入或输出错误消息,应该授权给UI线程来做,并将结果通知给worker线程。

     唯一能把数据安全交给线程的地方,就是heap

    (7)总结

    设计多线程程序的关键:

    1. 各线程的数据要分离开来,避免使用全局变量。
    2. 不要再线程之间共享GDI对象。
    3. 确定你知道你线程的状态。不要径自结束程序而不等待他们的结束。
    4. 让主线程处理用户界面(UI)
  • 相关阅读:
    190. Reverse Bits
    150. Evaluate Reverse Polish Notation
    【UML】状态图与活动图
    【UML】类图与对象图
    【UML】用例图
    【运维】Dell R710如何开启VT服务
    【运维】Dell R710如何做Raid0与Raid5
    【运维】略谈Raid级别
    【VMware vSphere】VMware vSphere简单了解
    【Linux】在Linux上安装VNC
  • 原文地址:https://www.cnblogs.com/kwliu/p/2195921.html
Copyright © 2020-2023  润新知