程序、进程和线程
程序:计算机指令的集合,以文件的形式存储在介质上
进程:一个正在运行的程序的实例
进程是资源申请、调度和独立运行的单位
进程的组成:
1.操作系统用来管理进程的内核对象,存放着进程的统计信息
2.地址空间,包含所有可执行文件或DLL模块的代码和数据,还包含动态内存分配的空间
进程地址空间
系统赋予每个进程独立的虚拟地址空间,对于32位进程来说,这个地址空间是4GB
每个进程有它自己私有的地址空间。
注意:4GB是虚拟地址空间,只是内存地址的一个范围,在你能够成功地访问数据而不会出现非法访问之间,必须赋予物理寄存器,或者将物理寄存器映射到各部分的地址空间
这里的所谓的物理寄存器包括两部分:
物理内存和页文件大小
页文件就是我们所谓虚拟内存:通过在磁盘上划分一块区域,从而增加了我们可以使用的内存的大小
4GB的虚拟地址空间的划分:
2GB是内核方式分区,供内核代码、设备驱动
程序、设备I/O高速缓存、非页面内存池的分配和进程页面表等使用
2GB是用户方式分配区
线程由两部分组成:
1.线程内核对象,操作系统用它来对线程实施管理,也是存放线程信息的地方
2.线程堆栈,用于维护线程执行代码时需要的所有参数和局部变量
防止竞态的方法
1.互斥对象
互斥对象(mutext)属于内核对象,它能够确保线程对单个资源的互斥访问权。
互斥对象的组成:
一个使用数量:
某线程拥有互斥对象的次数
一个线程ID:
标识系统当前那个线程拥有互斥对象
相关函数
1.创建一个互斥对象
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // 线程安全属性 BOOL bInitialOwner, // 互斥对象的拥有者,传递为FALSE表示无拥有者,即有信号状态 LPCTSTR lpName // 互斥对象的名称0 );
2.等待一个对象变为有信号状态
DWORD WaitForSingleObject( HANDLE hHandle, // 标识一个对象 DWORD dwMilliseconds // 超时值,为0立即返回,为INFINITE表示一直等待 );
3.释放一个互斥对象
BOOL ReleaseMutex( HANDLE hMutex // 互斥对象句柄 );
注意:互斥对象在哪个线程中获得信号就得在哪个线程中去释放信号,例如:在主线程调用了CreateMutex( NULL,TRUE,NULL);
由于第二参数设置为TRUE所以返回的互斥对象为主线程所拥有,如果此时又在主线程中创建了一个线程,而在此线程中你想调用
ReleaseMutex释放在主线程中创建的互斥对象是不可能的
注意:当在A线程中调用HANDLEA=CreateMutex(NULL,TRUE,NULL);的时候返回的互斥对象A的计数为1,如果此时我们在A线程中调用WaitForSingleObject(A,INFINITE).虽然现在互斥对象处于无信号状态但是我们仍可以请求到它,此时互斥对象的计数为2,此时我们需要调用两次ReleaseMutex()才能让互斥对象变为有信号状态
对于命名的互斥对象
实例:
有写程序只能同时运行一个实例,这个就可以通过命名的互斥对象来做到。
对于命名的互斥对象来说,一旦你再次创建同名的互斥对象
调用GetLastError后会返回ERROR_ALREADY_EXISTS,通过这一点我们就可以让一个进程只有一个实例在运行