实现线程同步的几种方法
2007-06-03 15:50
267 查看
1.程序、进程和线程
这是几个比较容易混淆的概念。
程序是计算机指令的集合,它以文件的形式存储在磁盘上。程序不能申请系统资源,不能被系统调度,也不能作为独立的运行单位。
进程是一个正在运行的程序实例,是一个程序在其自身的地址空间中的一次执行活动。我们编写的程序在编译后生成的后缀为.exe的可执行程序,是以文件的形式存储在磁盘上的,当运行这个可执行程序时,就启动了该程序的一个实例,即一个进程。进程是资源申请、调度和独立运行的单位,它使用系统中的运行资源。
线程的划分尺度小于进程,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,或只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
一个程序可以对应多个进程,一个进程至少包含一个线程。
2.多线程容易出现的问题
在包含多个线程的进程中,多个线程共享系统资源, 这种资源共享模式大大地节约了系统开销,但也造成了一个问提:就是各进程在资源访问过程中所有权的冲突问题。例如,时刻T1,线程1对资源A进行访问,在对其操作之前,CPU分配的时间片已到,系统将进程切换到线程2,假设线程2对资源A有一个写操作,那么当线程2结束,系统再次切换到线程1时,资源A已经发生了变化,此时线程1对资源A的操作就不是我们预想的操作了,因为这期间资源本身发生了变化。
为了解决资源共享模式下多个线程访问同一个资源的问题,就必须在多个线程之间实现一个同步处理,以保证一个线程访问这个资源时其他线程不能访问该资源。
3.线程同步的几种实现方法
(1).利用互斥对象实现线程同步
互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID和一个计数器。
利用互斥对象实现线程同步,首先必须创建一个互斥对象,调用CreateMutex函数,并设定该互斥对象的初始状态;在分线程中,线程必须主动申请共享对象的使用权才能获得该所有权,调用WaitForSingleObject函数来实现;当线程对共享资源访问结束后,应释放该对象的所有权,也就是让该对象处于已通知状态。
相关函数原形如下:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
BOOL ReleaseMutex(HANDLE hMutex);
DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
(2).利用事件对象实现线程同步
事件对象也属内核对象,它包含三个成员:使用计数;指明该事件是自动重置事件还是人工重置事件的标志位;指明该事件处于已通知状态还是未通知状态的标志位。
利用事件对象实现线程同步的过程与互斥对象大体相似:首先创建一个事件对象,调用CreateEvent函数;设置事件对象的状态,使用SetEvent函数;在分线程中调用WaitForSingleObject函数申请该对象的使用权;当线程结束后,调用ResetEvent函数重置事件对象状态。
相关函数原形如下:
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
关键代码段,也称为临界区,工作在用户方式下。它是指一小段代码段,在代码能够执行前,它必须独占对某些资源的访问权。
关键代码段的原理与公用电话亭比较类似。当我们要使用公用电话时,首先要判断电话亭里是否有人,如果有人正在使用,那么我们只有在外面等待;当那个人使用完电话并离开时,我们才能进入电话亭使用电话。利用关键代码段实现线程同步,首先要创建“公用电话亭”这一公用资源,即创建CRITICAL_SECTION类型的结构体;其次要对该关键代码段初始化,可以调用InitializeCriticalSection来实现;现在有了一个“公用电话亭”,要想进去“使用电话”,必须要判断里面是否有人,需要调用EnterCriticalSection函数;在使用完了电话后,我们要离开电话亭并交出电话的使用权,此时需要调用LeaveCriticalSection,通知其他人电话现在闲置了,可以用了。
相关函数原形如下:
(1).互斥对象和事件对象都属于内核对象,使用内核对象实现线程同步时,速度较慢,但可以在多个进程中的各个线程间进行同步
(2).关键代码段工作在用户方式下,同步速度较快,但容易进入死锁状态
5.关于内核对象
内核对象是系统用来存放关于进程的统计信息的地方,是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息。由于内核对象只能被内核访问使用,因此应用程序在内存中无法找到该数据结构,并直接改变其内容,只能通过Windows提供的一些函数来对内核对象进行操作。
这是几个比较容易混淆的概念。
程序是计算机指令的集合,它以文件的形式存储在磁盘上。程序不能申请系统资源,不能被系统调度,也不能作为独立的运行单位。
进程是一个正在运行的程序实例,是一个程序在其自身的地址空间中的一次执行活动。我们编写的程序在编译后生成的后缀为.exe的可执行程序,是以文件的形式存储在磁盘上的,当运行这个可执行程序时,就启动了该程序的一个实例,即一个进程。进程是资源申请、调度和独立运行的单位,它使用系统中的运行资源。
线程的划分尺度小于进程,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,或只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
一个程序可以对应多个进程,一个进程至少包含一个线程。
2.多线程容易出现的问题
在包含多个线程的进程中,多个线程共享系统资源, 这种资源共享模式大大地节约了系统开销,但也造成了一个问提:就是各进程在资源访问过程中所有权的冲突问题。例如,时刻T1,线程1对资源A进行访问,在对其操作之前,CPU分配的时间片已到,系统将进程切换到线程2,假设线程2对资源A有一个写操作,那么当线程2结束,系统再次切换到线程1时,资源A已经发生了变化,此时线程1对资源A的操作就不是我们预想的操作了,因为这期间资源本身发生了变化。
为了解决资源共享模式下多个线程访问同一个资源的问题,就必须在多个线程之间实现一个同步处理,以保证一个线程访问这个资源时其他线程不能访问该资源。
3.线程同步的几种实现方法
(1).利用互斥对象实现线程同步
互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID和一个计数器。
利用互斥对象实现线程同步,首先必须创建一个互斥对象,调用CreateMutex函数,并设定该互斥对象的初始状态;在分线程中,线程必须主动申请共享对象的使用权才能获得该所有权,调用WaitForSingleObject函数来实现;当线程对共享资源访问结束后,应释放该对象的所有权,也就是让该对象处于已通知状态。
相关函数原形如下:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
BOOL ReleaseMutex(HANDLE hMutex);
DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
(2).利用事件对象实现线程同步
事件对象也属内核对象,它包含三个成员:使用计数;指明该事件是自动重置事件还是人工重置事件的标志位;指明该事件处于已通知状态还是未通知状态的标志位。
利用事件对象实现线程同步的过程与互斥对象大体相似:首先创建一个事件对象,调用CreateEvent函数;设置事件对象的状态,使用SetEvent函数;在分线程中调用WaitForSingleObject函数申请该对象的使用权;当线程结束后,调用ResetEvent函数重置事件对象状态。
相关函数原形如下:
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
(3).利用关键代码段实现线程同步
关键代码段,也称为临界区,工作在用户方式下。它是指一小段代码段,在代码能够执行前,它必须独占对某些资源的访问权。
关键代码段的原理与公用电话亭比较类似。当我们要使用公用电话时,首先要判断电话亭里是否有人,如果有人正在使用,那么我们只有在外面等待;当那个人使用完电话并离开时,我们才能进入电话亭使用电话。利用关键代码段实现线程同步,首先要创建“公用电话亭”这一公用资源,即创建CRITICAL_SECTION类型的结构体;其次要对该关键代码段初始化,可以调用InitializeCriticalSection来实现;现在有了一个“公用电话亭”,要想进去“使用电话”,必须要判断里面是否有人,需要调用EnterCriticalSection函数;在使用完了电话后,我们要离开电话亭并交出电话的使用权,此时需要调用LeaveCriticalSection,通知其他人电话现在闲置了,可以用了。
相关函数原形如下:
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
4.以上几种方法的比较
(1).互斥对象和事件对象都属于内核对象,使用内核对象实现线程同步时,速度较慢,但可以在多个进程中的各个线程间进行同步
(2).关键代码段工作在用户方式下,同步速度较快,但容易进入死锁状态
5.关于内核对象
内核对象是系统用来存放关于进程的统计信息的地方,是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息。由于内核对象只能被内核访问使用,因此应用程序在内存中无法找到该数据结构,并直接改变其内容,只能通过Windows提供的一些函数来对内核对象进行操作。
相关文章推荐
- 线程同步的几种实现方法
- Silverlight 2.0使用Lock, Interlocked, EventWaitHandle, Monitor来实现线程同步//C#线程同步的几种方法
- 归纳一下:C#线程同步的几种方法
- 多线程编程--5种方法实现线程同步
- PHP解决并发问题的几种实现方法
- 几种网页上实现返回上一页的方法
- 二维数组遍历的几种实现方法
- ios实现颜色渐变的几种方法
- Android实现异步的几种方法
- CXF客户端的几种实现方法
- 多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
- 实现性能目标的几种方法
- ASP.NET MVC中实现多个按钮提交的几种方法
- 【转】C#抽象工厂模式的几种实现方法及比较
- 一起谈.NET技术,【经验总结】C#常用线程同步方法应用场景和实现原理
- Android亮度调节的几种实现方法
- ASP.NET实现页面间值传递的几种方法介绍
- 标签栏的几种实现方法(推荐)
- ios实现颜色渐变的几种方法