进程与线程;同步与互斥:事件,信号量,临界区,互斥量

进程


一个正在执行的程序
计算机中正在运行的程序的一个实例
可以分配给处理器并且由处理器执行的一个实体
由一个顺序执行的代码段、一个当前状态和一组相关系统资源所刻画的活动单元

进程是操作系统资源分配的基本单位

线程


进程中代码执行的一个序列

线程是操作系统可以进行运算调度的基本单位

进程、线程的区别


1. 划分尺度不同。线程是进程的一部分。一个进程至少包含一个线程,可以有多个线程。
2. 资源分配不同。进程是资源分配的基本单位,同一进程的线程共享其进程的代码、数据及文件等资源,而线程仅拥有自己的寄存器和栈,除了CPU外线程与任何系统资源分配都无关。
3. 地址空间不同。系统在运行时会为每个进程分配内存空间,进程有独立的地址空间,但线程没有,多个线程共享内存。
4. 执行过程不同。每个独立的线程有一个程序运行的入口、顺序执行序列和程序出口。但线程却不能独立执行,需要依附于应用程序。

同步


同步是指线程之间的一种制约关系,线程A的执行需要线程B的消息,在没有收到线程B的消息时应等待,直到消息到达。

事件


事件是一个内核对象,可以跨进程使用。

事件被分为:手动置位和自动置位。手动置位是同时向所有等待线程发信号通知,某一操作已经做完了,使他们都处于有信号的状态,都成为可调度线程;自动置位是向某一线程发信号,使它为有信号状态,成为可调度线程。

创建事件
/*
	lpEventAttributes 事件的安全级别,设为NULL为默认设置
	bManualReset 人工置位为true,自动置位为false
	bInitialState 事件初始化的状态,有状态为true,无状态为false
	lpName 事件的名称,设为NULL则为匿名
*/
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
                   BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);

设置事件为有状态
BOOL SetEvent(HANDLE hEvent);
对于手动置位的事件,SetEvent方法将解锁在该事件上等待的所有线程,即当人工重置变为有信号时,所有的等待该事件的线程都变为可调度线程,将保持有信号状态,直到某事件手动置位为无状态。对于自动置位的事件,SetEvent方法将仅解锁一个线程,通过调用WaitForSingleObject()自动调用Reset()方法使事件变为无信号状态。

设置事件为无状态
BOOL ResetEvent(HANDLE hEvent);

信号量


信号量是内核对象,可用于进程间的同步也可用于同一进程中的线程间的同步,用来对资源进行计数。当资源数大于零,信号量处于触发状态;当资源是等于零,信号量未触发。

创建信号量
/*
	lpSemaphoreAttributes 信号量的安全属性,设为NULL则为默认设置
	lInitialCount 初始资源数,必须大于等于零,小于最大资源数
	lMaximumCount 最大资源数
	lpName 信号量名称,设为NULL则为匿名信号量
*/
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);

打开一个已有信号量
/*
	dwDesiredAccess 访问方式,一般使用SEMAPHORE_ALL_ACCESS
	bInheritHandle 继承特性,一般使用true
	lpName 信号量名称
*/
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

释放信号量
/*
	hSemaphore 要释放的信号量句柄
	lReleaseCount 释放的数量,即资源的增加量,必须大于零
	lpPreviousCount 原先的计数值,设为NULL为不需要传入
*/
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

互斥


对于共享的资源,每个进程访问时具有排他性。对于共享资源任何时刻仅允许一个线程访问,其他线程想要访问则必须等待,直到占用资源的线程释放了该资源。互斥可以认为是一种特殊的同步。

临界区


临界区保护一段代码不被多于一个线程访问。

临界区相关函数
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 初始化临界区
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 进入临界区
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 离开临界区
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); // 删除临界区

因为主线程拥有线程所有权,所以可以重复多次进入临界区,导致子线程在接受参数之前主线程可能已经修改了参数,而无法实现线程同步。

互斥量


互斥量是一个内核对象,用来确保资源仅被一个线程访问,可以跨进程访问。

创建互斥量
/*
 lpMutexAttributes 安全控制,设为NULL则为默认设置
 bInitialOwner 是否成为该互斥量的初始拥有者,设为TRUE为拥有,互斥量为无信号状态;设为FALSE为不拥有,该信号量不为任何线程占有,互斥量为有信号状态
 lpName 互斥量名称
*/
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);

打开互斥量
/*
 dwDesiredAccess 访问方式,一般设为MUTEX_ALL_ACCESS
 bInheritHandle 该进程的子进程能否继承该互斥量,一般设为TRUE
 lpName 互斥量名称
*/
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

释放互斥量
BOOL ReleaseMutex(HANDLE hMutex);

互斥量同临界区一样,主线程拥有线程控制权,因此同样不能用于同步。
互斥量可以解决因线程意外终止而造成的遗弃现象。具体来说,如果一个线程在释放互斥量之前因某些意外终止,照理来说应该互斥量还要能够被其他等待的线程使用,否则会陷入无限的等待,这是不合理的。因此,在这样的情况下,系统会将互斥量的状态设为有信号状态,这样其他线程就可以使用了。


小结


事件:用于通知其他线程事件已发生,从而启动线程
信号量:可以对资源进行计数,允许多个线程共享资源,限制了同一时刻多个线程能访问的最大资源数。
临界区:在任一时刻仅允许一个线程使用临界区资源。四者中仅有临界区不是内核对象。适合于数据访问的控制。
互斥量:拥有互斥量才可以访问共享资源,因此共享资源不会被多个线程所共享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值