多线程,进程,模块,

2019-04-13 21:14发布

多线程 1、回调函数: 若类成员函数是一个callback函数,必须声明为static.才能将C++编译器加于函数的一个隐藏参数this去掉。Windows系统调用的函数统称为callback函数,这些函数都有一定的类型。Windowsi并不借助任何对象调用这个函数,没有传递this指针给callback函数。于是堆栈中有一个随机变量会成为this 指针,直接的是程序的崩溃 2、进程、模块、线程之间的关系: 每一个进程都有两个很重要的部分组成MODERefList是所有的模块链表结构体相连。每个结构体都指向pModuleTableArray中的某一项。当然其中放置的是数组的索引。注意不是索引。在这个MOduleTable中每一个又指向TMTES。数组中第一项指的是KENRNEL32.DLL. 这个dllWindows加载器将程序加载在内存中,会挖出一些内存,构建一个PDV,一个TDB,一个一霎呢的MDBs。针对TDB,操作系统又要创建消息队列、Handle表格、环境数据结构。当这些系统内部数据结构都构建完毕,指令指位器移到程序的进入点、才开始程序的执行。 3、进程概述:  进程分为系统进程(管态)和用户进程(目态).用户进程是不能够直接的操作I/O的。  进程控制块;存放进程的管理和控制信息的数据结构。是进程管理和控制的最重要的数据结构,在创建,建立PCB,并伴随进程运行的全过程。直到进程撤销而撤销。进程与PCB是一一对应的。进程控制块包括进程标志信息。处理器状态信息、进程控制信息。就绪、运行、阻塞。 4、进程有两部分组成:内核对象与地址空间 内核对象:操作系统用来管理进程,存放关于进程的统计信息的地方,是系统内部分配的一个内存快,只能由windows中的相关函数进行操作,而不能直接的操作。其内部有一个布尔变量,当系统创建这个内核对象的时候会将这个变量的值初始化为FALSE,表示为未触发的状态。当进程终止的时候,操作西戎会自动把相应的内核对象中这个布尔值设为true,注意内核对象中包括有:进程、线程、作业、互斥量、事件等。在进程的内核对象中保存的是一个进程ID、基本的优先级和一个退出代码。创建一个内核对象,系统就将会为其分配内存。  地址空间:包含所有的可执行模块的代码(指令表执行和CPU状态的改变)和数据(变量的生成和赋值)、系统控制信息(进程控制块的生成和删除)。包含动态内存分配空间,线程的堆和栈。     (1) 每个进程独立的虚拟的4GB空间,拥有私有的地址空间。有存放自己地址空间的数据结构。所谓虚拟的就是当你真正要操作这些数据的时候你要到相应的物理盘中寻找,进行映射这里的物理存储器包括内存与页文件大小。 (2)  4GB的虚拟内存空间,2GB是内核方式分区。供内核代码、设备驱动程序、设备I/O高速缓冲、进程页面表等使用,用户方式地址空间约2GB,私有地址。另一些则是UNLL指针分区,进程不可读、写,是维护进程的大部分数据地方 4线程:同样的包括两部分的内容:内核对象与线程栈。 1) 内核对象:存放线程信息。 2) 线程栈:维护线程在执行代码时需要的所有函数参数和局部变量。创建线程,系统会创建一个线程内核对象,是一个管理线程的小数据结构。可以访问进程中的所有句柄,以及其他线程的堆栈。 当创建一个线程时,系统会为线程分配一个ID,若将此参数传递NULL,表示对ID没有兴趣,于是不会返回线程的标识符。 在创建一个线程的时候返回的是句柄,那么利用CloseHandle并没有中止新创建的线程。只是表示在主线程中对新创建的线程的引用不感兴趣,因此将其关闭,同时这个时候可以减少内核对象的使用计数。 1)  创建线程:在我们创建新的线程的时候最好的是继承现有的CWindThread对象。利用这个对象中的CreateThread创建新的线程。为什么呢?是否因为在类的构造函数中进行了其它的操作。所以才不用原来的::CreateTread呢?是的。在AfxBeginThread中会调用CreateThread这个函数。 2) 等待线程被唤醒的时机:1、等待的时间最长,但是在线程先等待然而后面被挂起的状况下,系统会忽略这个线程。 5、其他的内核对象 1) 互斥对象 1. HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttribute, BOOL nInitialOwner,//若值为真,则创建这个互斥对象的线程获得该对象的所有权。 LPCTSTR lpName); ReleaseMutex(HANDLE hMutex);//释放的是句柄,会将计数减1 2WaitForSingleObject(HANDLE hHandle,//主动请求共享对象的使用权,当互斥对象有信号。返回。此时将会将这个共享对象的内核计数增加1.在它的持续等待时间中并不会浪费CPU的时间。   DWORD dwMillisecods);//若指定的时间间隔已过,亦返回。将参数设置为INFINITE,函数一直等待。直到有信号 当创建的时候是false时没有任何的县城拥有这个互斥对象,当一个wait到知道,系统会将其对应的线程ID赋给这个互斥对象,此时若没有释放,那么其它的线程就不能够获得这个互斥对象,这个时候相当于是P操作。 若是true,如果在创建之后才开始创建新的线程,那么很糟糕的情况出现,就是没有一个新创建的线程可以获得这个拥有权,除非在这个创建互斥对象的主线程中进行互斥对象的释放。于是我们知道想要释放某个互斥对象必须是拥有了这个互斥对象的线程进行释放。在将互斥对象的线程ID置于这个ID之后,同样的我们可以推测出其相应的对象计数也增加1 线程终止,操作系统会将这个线程拥有的互斥对象的线程ID设置为0。并将计数归0 2)  事件对象 1. CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManalReset,//人工重置的对象得到通知,等待该时间的所有线程均变为可调度的,也就是说可以在同一时刻有几个线程的同时运行。在手动情况下,调用SetEvent之后,几个线程可以同时的访问内存,但是仅限于只读方式的访问内存。在自动的状态下,系统会自动的调用SetEvent。自动设置则只有一个被调用。 BOOL bInitialState,//若是真,则时间对象的初始是有新号状态,否则为无信号状态,               这个意思就是说被挂起。没有会得到这个对象。与之前的互斥对象一样,只有在有信号 LPCTSTR lpName);   //的时候才可继续执行。 2. SetEvent();//将事件转为触发状态。也就是说现在没有对象在使用这个事件,内核计数为0返回一个事件内核对象句柄,句柄与当前的进程相关。无线程在使用这个对象。 3. ResetEvent();//将事件转为非触发态。内核计数为1.那么其他的访问将会被挂起。也就是有线程在使用这个对象 关键代码段: LeaveCriticalSection()