实习一:多进程(线程)实现快速排序 - bbsverticalsearch

Download Report

Transcript 实习一:多进程(线程)实现快速排序 - bbsverticalsearch

实习1:并发控制
多生产者消费者问题
2015年4月12日星期日
题目说明(1)
•问题描述
– 有M个生产者,N个消费者,每个生产者每次生
产一个产品,每个消费者每次消费一个产品
– 存放产品的缓冲区可容纳K个产品
– 对于生产者生产的每一个产品,每个消费者必须
消费且仅能消费一次
2015年4月12日星期日
题目说明(2)
•要求
– 在Windows环境下实现上述问题
– 使用两种方式来实现:进程,线程
– 将运行的过程及结果以文本方式或直接向控制台
输出。具体内容包括(但不限于):
• 每个生产者/消费者的一次生产/消费行为
• 每个生产者生产的产品
• 每个消费者消费的产品
• 每个消费者消费的产品来源(来自哪个生产者)
– 输出顺序与生产/消费顺序相同
2015年4月12日星期日
相关知识
Windows提供了以下4种对象
互斥对象
信号量对象
事件对象
CriticalSection对象






用户在使用这些对象时,需要指定对象的名称
,不同进程中用同样的对象名称来创建或打开
对象,从而获得该对象的句柄
你需要从中选择一种或几种来完成本次实验
2015年4月12日星期日
思考题
• 在完成实习的同时,你还需要回答以下问题
– 使用进程和线程两种方式完成该实习的过程中,
你分别使用了哪种(或哪几种)Windows对象?选
用该对象的理由是什么?
– 试分析:使用进程方式解决本次实习问题时,如
果分别采用上述几种同步对象,解决问题的过程
是否会有不同?(包括代码逻辑、实现的难易程度
等) 如果使用线程,又会有什么不同?
2015年4月12日星期日
相关知识
•互斥对象(Mutex)就是互斥信号量,在一个时刻
只能被一个线程使用
•它的相关API包括:CreateMutex、OpenMutex
和ReleaseMutex
–CreateMutex创建一个互斥对象,返回对象句柄
–OpenMutex打开并返回一个已存在的互斥对象句柄
,用于后续访问
–ReleaseMutex释放对互斥对象的占用,使之成为可用
2015年4月12日星期日
相关知识
•信号量对象(Semaphore)就是资源信号量,取值
的取值在0到指定最大值之间,用于限制并发访
问的线程数
•它的相关API包括:CreateSemaphore、
OpenSemaphore和ReleaseSemaphore
–CreateSemaphore创建一个信号量对象,在输入参数
中指定最大值和初值,返回对象句柄
–OpenSemaphore返回一个已存在的信号量对象的句柄
,用于后续访问
–ReleaseSemaphore释放对信号量对象的占用
2015年4月12日星期日
相关知识
• 事件对象(Event)相当于“触发器”,可用于通知
一个或多个线程某事件的出现
• 它的相关的API包括:CreateEvent、OpenEvent、
SetEvent、ResetEvent和PulseEvent
–CreateEvent创建一个事件对象,返回对象句柄
–OpenEvent返回一个已存在的事件对象的句柄,用于后
续访问
–SetEvent和PulseEvent设置指定事件对象为可用状态
–ResetEvent设置指定事件对象为不可用状态
2015年4月12日星期日
相关知识
• 对于以上三种同步对象,Windows 提供了两个统一
的等待操作:
• WaitForSingleObject和WaitForMultipleObjects
–WaitForSingleObject可在指定的时间内等待指定
对象为可用状态
–WaitForMultipleObjects可在指定的时间内等待
多个对象为可用状态
2015年4月12日星期日
相关知识
• 这两个API的接口为:
DWORD WaitForSingleObject( HANDLE hHandle, //
等待对象句柄
DWORD dwMilliseconds// 以毫秒为单位的最长等待时间
);
DWORD WaitForMultipleObjects( DWORD nCount,
//对象句柄数组中的句柄数;
CONST HANDLE *lpHandles,
// 指向对象句柄数组的指针,数组中可包括多种对象句柄;
BOOL bWaitAll,
// 等待标志:TRUE表示所有对象同时可用,FALSE表示至少
一个对象可用;
DWORD dwMilliseconds // 等待超时时限;
);
2015年4月12日星期日
相关知识
• Critical Section对象:只能在同一进程内使用的临
界区,同一进程内各线程对它的访问是互斥进行的。
把变量说明为CRITICAL_SECTION类型,就可作
为临界区使用。有关的API:
–InitializeCriticalSection对临界区对象进行初始化
–EnterCriticalSection等待占用临界区的使用权,得到使
用权时返回
–TryEnterCriticalSection非等待方式申请临界区的使用权;
申请失败时,返回0
–LeaveCriticalSection释放临界区的使用权
–DeleteCriticalSection释放与临界区对象相关的所有系统
资源
2015年4月12日星期日
相关知识
• 互锁变量访问:相当于硬件指令,对一个整数
(进程内的变量或进程间的共享变量)进行操作。
其目的是避免线程间切换的影响。有关的API:
–InterlockedExchange进行32位数据的先读后写原子操作
–InterlockedCompareExchange依据比较结果进行赋值的
原子操作
–InterlockedExchangeAdd先加后存结果的原子操作
–InterlockedDecrement先减1后存结果的原子操作
–InterlockedIncrement先加1后存结果的原子操作
2015年4月12日星期日
API
CreateMutex
• 说明:创建一个互斥对象
• 返回值:如执行成功,就返回互斥体对象的句柄;
零则表示出错
• 参数
lpMutexAttributes :指向
SECURITY_ATTRIBUTES 结构的指针,该结构决
定子进程师父能继承返回句柄。若
lpMutexAttributes为NULL,则该句柄不能被继承
bInitialOwner :若创建进程希望立即拥有该互斥
对象,则设为TRUE ;否则设为FALSE
lpName :互斥对象的名字
2015年4月12日星期日
API(续)
OpenMutex
•说明:打开存在的已命名的互斥对象
•返回值:若成功,则返回互斥对象的句柄;
否则返回NULL
•参数
dwDesiredAccess :指定对请求的互斥对象的
访问方式。MUTEX_ALL_ACCESS表示可
以对该互斥对象进行所有可能的访问标记
bInheritHandle:指明返回句柄是否可以继承
lpName:要打开的互斥对象的名字
2015年4月12日星期日
API(续)
CreateSemaphore
•说明:创建一个信号量对象
•返回值:若执行成功,则返回信号量对象的
句柄;零则表示出错参数
lpSemaphoreAttributes :定义了信号机的安
全特性,指向SECURITY_ATTRIBUTES结
构,若为NULL则表示使用默认属性
lInitialCount :设置信号量的初始计数
lMaximumCount:设置信号量的最大计数
lpName :信号量对象的名称
2015年4月12日星期日
API(续)
OpenSemaphore
•说明:用于打开一个已经存在的命名信号量
•返回值:返回该信号量对象的句柄
•参数
dwDesiredAccess:指明对所请求信号量的访
问,其中SEMAPHORE_ALL_ACCESS表示
对该信号量对象所有可能访问标记
bInheritHandle :指明返回句柄是否可继承
lpName:要打开信号量对象的名字
2015年4月12日星期日
API(续)
ReleaseSemaphore
•说明:增加信号量的计数
•返回值:若成功则返回非零值,否则返回零
•参数
hSemaphore :信号量对象的句柄
lReleaseCount:信号量对象的增额
lpPreviousCount:指向某个用于检索信号量
的前一个值的变量
2015年4月12日星期日
API(续)
WaitForSingleObjects
• 说明:当指定对象处于有信号状态或者超时的时候,
该函数返回
• 返回值:若成功,返回值表明引起函数返回的时间,
可能为WAIT_ABANDONED,WAIT_OBJECT_0
和WAIT_TIMEOUT;若函数失败,返回
WAIT_FAILED
• 参数
hHandle:等待对象句柄
dwMilliseconds:指定以毫秒为单位的超时间隔
2015年4月12日星期日
API(续)
WaitForMultipleObjects
• 说明:当任意一个或全部指定对象处于有信号状态
或者超时,则该函数返回
• 返回值:若函数成功,返回值表明引起函数返回的
事件
• 参数
nCount:指明由lpHandles所指向的数组中的对象句
柄数目
lpHandles:对象句柄数组的指针
fWaitAll:指明等待类型
dwMilliSeconds:指明以毫秒为单位的超时间隔
2015年4月12日星期日
API(续)
InitializeCriticalSection
•说明:该函数用于初始化临界区对象
•备注:单进程的所有线程可以使用互斥同步
机制的临界区对象,但是不能保证线程获得
临界区所有权的顺序
•参数
lpCriticalSection:指向临界区对象的指针
2015年4月12日星期日
API(续)
EnterCriticalSection
•说明:该函数用于等待指定临界区对象的所
有权,当调用线程被赋予所有权时,该函数
返回
•参数
lpCriticalSection:指向临界区对象的指针
2015年4月12日星期日
API(续)
LeaveCriticalSection
•说明:该函数用于释放指定临界区对象的所
有权
•参数
lpCriticalSection:指向临界区对象的指针
2015年4月12日星期日
API(续)
CloseHandle
•说明:关闭一个内核对象
•返回值:非零表示成功,零表示失败
•参数
hObject :欲关闭的一个对象的句柄
2015年4月12日星期日
API(续)
Sleep
•说明:改函数用于在指定的时间间隔挂起当
前的执行线程
•返回值:无
•参数
dwMilliseconds:定义挂起执行线程的时间,
以毫秒为单位
2015年4月12日星期日
API(续)
CreateProcess
• 说明
创建一个新进程(比如执行一个程序)
• 返回值
Long,非零表示成功,零表示失败。会设置GetLastError
• 参数
lpCommandLine :String,要执行的命令行。可用
GetCommandLine函数取得一个进程使用的命令行。
Windows会尽可能地根据下述搜索顺序来查找执行文件:
(1)包含了父进程执行文件的目录
(2)父进程当前的目录
(3)由GetSystemDirectory返回的系统目录
(4)仅适于windows NT:16位系统目录
(5)由GetWindowDirectory返回的Windows目录
(6)由PATH环境变量指定的目录
2015年4月12日星期日
dwCreationFlags :
1.若设为CREATE_SUSPENDED ,则立即挂起新进
程。除非调用了ResumeThread函数函数,否则它
不会恢复运行
2.也可能是下述常数之一,用于指定优先级 :
IDLE_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
lpStartupInfo :STARTUPINFO,指定一个
STARTUPINFO结构,其中包含了创建进程时使用
的附加信息
lpProcessInformation :PROCESS_INFORMATION,
该结构用于容纳新进程的进程和线程标识符。大多
数情况下,一旦这个函数返回,父应用程序都会关
闭两个句柄
2015年4月12日星期日
API(续)
CreateThread
• 说明:创建一个在调用进程的地址空间中执行的线程
• 参数
lpStartAddress:指向一个
LPTHREAD_START_ROUTINE类型的应用定义的
函数,该线程执行此函数
dwCreationFlags:定义控制线程创建的附加标志。若
定义了CREATE_SUSPENDED标志,线程创建后便
处于挂起状态,直到ResumeThread函数调用时才能
运行。若该值为0,则该线程创建后立即执行
lpThreadId:线程标识符
2015年4月12日星期日