Windwos 多线程程序设计 多线程概述 Win32 API对多线程编程的支持 线程之间的同步 哲学家进餐问题分析与实现.

Slides:



Advertisements
Similar presentations
7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
Advertisements

面向侧面的程序设计 方林博士 本文下载地址:
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
软件开发技术基础 第 3 章 操作系统及程序设计 讲授教师:卫颜俊. 主 要 内 容 主 要 内 容 操作系统及其功能 进程管理应用程序设计 内存管理应用程序设计 设备与文件管理应用程序设计 人机接口管理应用程序设计.
Linux 系统. 操作系统发展需求 1 没有操作系统 2 简单批处理操作系统 3 多道程序设计的批处理 4 多道程序设计的分时操作系统 5 多处理机并行系统 6 网络操作系统 7 分布式操作系统.
实用操作系统概念 张惠娟 副教授 1.
Oracle数据库 Oracle 子程序.
第三章 Windows多线程编程.
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
OpenMP简介和开发教程 广州创龙电子科技有限公司
Visual C++ Windows Programming
多核结构与程序设计 杨全胜 东南大学成贤学院计算机系.
动态链接库 多线程 文件操作 注册表 多媒体编程 Winsock编程(网络编程) 数据库.
互斥与同步 操作系统实验2
存储系统.
实践演练 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
走进编程 程序的顺序结构(二).
辅导课程六.
网络常用常用命令 课件制作人:谢希仁.
临界区软件互斥软件实现算法.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
临界区软件互斥软件实现算法 主讲教师:夏莹杰
CPU结构和功能.
Windows 7 的系统设置.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
Unit 11.Operating System 11.1 What’s OS 11.2 Related Courses
程序设计工具实习 Software Program Tool
实验二、线程同步与通信 一、实验目的 1、掌握Linux下线程的概念; 2、了解Linux线程同步与通信的主要机制;
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
内容摘要 ■ 课程概述 ■ 教学安排 ■ 什么是操作系统? ■ 为什么学习操作系统? ■ 如何学习操作系统? ■ 操作系统实例
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
实验四、TinyOS执行机制实验 一、实验目的 1、了解tinyos执行机制,实现程序异步处理的方法。
姚金宇 MIT SCHEME 使用说明 姚金宇
分裂对象模型 C++ otcl.
Select模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
信号量(Semaphore).
解决“最后1公里”问题.
iSIGHT 基本培训 使用 Excel的栅栏问题
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 文件系统 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
Visual Basic程序设计 第13章 访问数据库
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
3.1私有内存的分配.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
互斥与同步 操作系统实验2
本节内容 消息的接收 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
_08文件操作 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
WSAAsyncSelect 模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
第9章 多 线 程.
Google的云计算 分布式锁服务Chubby.
_07多连接之select模型 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
阻塞式模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
MFC的六大核心 机制 命令传递 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Chinese Virtual Observatory
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 SEMAPHORE 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
Presentation transcript:

Windwos 多线程程序设计 多线程概述 Win32 API对多线程编程的支持 线程之间的同步 哲学家进餐问题分析与实现

1、多线程概述(1) 进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。 线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。主执行线程终止了,进程也就随之终止。

多线程概述(2) 每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。 多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。

多线程概述(3)  Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。

2、Win32 API对多线程编程的支持 CreateThread SuspendThread ResumeThread和 ExitThread GetExitCodeThread TerminateThread WaitForSingleObject WaitForMultipleObjects

CreateThread的原型 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);

CreateThread的参数 该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄 HANDLE LPSECURITY_ATTRIBUTES lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL; DWORD dwStackSize:指定了线程的堆栈深度,一般都设置为0; LPTHREAD_START_ROUTINE lpStartAddress :表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名; LPVOID lpParameter :指定了线程执行时传送给线程的32位参数,即线程函数的参数; DWORD dwCreationFlags :控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用; LPDWORD lpThreadId lpThreadId:该参数返回所创建线程的ID; 如果创建成功则返回线程的句柄,否则返回NULL。

SuspendThread DWORD SuspendThread(HANDLE hThread); 该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被挂起。

ResumeThread和 ExitThread DWORD ResumeThread(HANDLE hThread);该函数用于结束线程的挂起状态,执行线程。 VOID ExitThread(DWORD dwExitCode); 该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。

GetExitCodeThread 功能: 获取一个结束线程的返回值 原形: BOOL GetExitCodeThread( HANDLE hThread,  LPDWORD lpExitCode); 参数:hThread 指向欲获取返回值的线程对象的句柄 lpExitCode 用于存储线程的返回值 STILL_ACTIVE 表示线程还在运行,其他值表示线程的返回值 返回值:函数执行成功则返回非0值,否则返回 0(FALSE)

TerminateThread BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

WaitForSingleObject DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); hHandle为要监视的对象(一般为同步对象,也可以是线程)的句柄; dwMilliseconds为hHandle对象所设置的超时值,单位为毫秒; 当在某一线程中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态。如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。

WaitForMultipleObjects DWORD WaitForMultipleObjects( DWORD nCount, // 等待的对象数量 CONST HANDLE *lpHandles, // 对象句柄数组指针 BOOL fWaitAll, // 等待方式,为TRUE表示等待全部对象都变为有信号状态才返回,为FALSE表示任何一个对象变为有信号状态则返回 DWORD dwMilliseconds // 超时设置,以ms为单位,如果为INFINITE表示无限期的等待 ); 返回值意义: WAIT_OBJECT_0 到 (WAIT_OBJECT_0 + nCount – 1):当fWaitAll为TRUE时表示所有对象变为有信号状态,当fWaitAll为FALSE时使用返回值减去WAIT_OBJECT_0得到变为有信号状态的对象在数组中的下标。 WAIT_ABANDONED_0 到 (WAIT_ABANDONED_0 + nCount – 1):表示对象中有一个对象为互斥量,该互斥量因为被关闭而成为有信号状态,使用返回值减去WAIT_ABANDONED_0得到变为有信号状态的对象在数组中的下标。 WAIT_TIMEOUT:表示超过规定时间。

线程之间的同步 各个线程可以访问进程中的公共变量,所以使用多线程的过程中需要注意的问题是如何防止两个或两个以上的线程同时访问同一个数据,以免破坏数据的完整性。保证各个线程可以在一起适当的协调工作称为线程之间的同步。前面一节介绍的事件对象实际上就是一种同步形式。 临界区(critical section) 互斥体(Mutexes) 信号量(Semaphore) 事件(Event)

临界区(CRITICAL_SECTION) 临界区是保证在某一个时间只有一个线程可以访问数据的方法。使用它的过程中,需要给各个线程提供一个共享的临界区对象,无论哪个线程占有临界区对象,都可以访问受到保护的数据,这时候其它的线程需要等待,直到该线程释放临界区对象为止,临界区被释放后,另外的线程可以强占这个临界区,以便访问共享的数据。用临界区对象:

临界区的操作函数 VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection );产生临界区 VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection );删除临界区 VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection );进入临界区,相当于申请加锁,如果该临界区正被其他线程使用则该函数会等待到其他线程释放 BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection );进入临界区,相当于申请加锁,和EnterCriticalSection不同如果该临界区正被其他线程使用则该函数会立即返回FALSE,而不会等待 VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection );退出临界区,相当于申请解锁

互斥体(MUTEXS) 互斥体与临界区很相似,但是使用时相对复杂一些,它不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。

互斥量的操作函数(建立与打开) 创建互斥量: 打开一个存在的互斥量: HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes,// 安全信息 ,NULL表示默认属性 BOOL bInitialOwner, // 最初状态,如果设置为真,则表示创建它的线程直接拥有了该互斥量,而不需要再申请 LPCTSTR lpName // 名字,可以为NULL,但这样一来就不能被其他进程打开 ); 打开一个存在的互斥量: HANDLE OpenMutex( DWORD dwDesiredAccess, // 存取方式 BOOL bInheritHandle, // 是否可以被继承 LPCTSTR lpName // 名字 );

互斥量的操作函数(释放与关闭) 释放互斥量的使用权,但要求调用该函数的线程拥有该互斥量的使用权: 关闭互斥量: BOOL ReleaseMutex(HANDLE hMutex // 句柄 ); 关闭互斥量: BOOL CloseHandle( HANDLE hObject // 句柄 );

获取互斥量的使用权 (1) DWORD WaitForSingleObject( HANDLE hHandle, // 等待的对象的句柄 DWORD dwMilliseconds // 等待的时间,以ms为单位,如果为INFINITE表示无限期的等待 ); 返回: WAIT_ABANDONED 在等待的对象为互斥量时表明因为互斥量被关闭而变为有信号状态 WAIT_OBJECT_0 得到使用权 WAIT_TIMEOUT 超过(dwMilliseconds)规定时间

获取互斥量的使用权 (2) DWORD WaitForMultipleObjects( DWORD nCount, // 等待的对象数量 CONST HANDLE *lpHandles, // 对象句柄数组指针 BOOL fWaitAll, // 等待方式,为TRUE表示等待全部对象都变为有信号状态才返回,为FALSE表示任何一个对象变为有信号状态则返回 DWORD dwMilliseconds // 超时设置,以ms为单位,如果为INFINITE表示无限期的等待 ); 返回值意义: WAIT_OBJECT_0 到 (WAIT_OBJECT_0 + nCount – 1):当fWaitAll为TRUE时表示所有对象变为有信号状态,当fWaitAll为FALSE时使用返回值减去WAIT_OBJECT_0得到变为有信号状态的对象在数组中的下标。 WAIT_ABANDONED_0 到 (WAIT_ABANDONED_0 + nCount – 1):表示对象中有一个对象为互斥量,该互斥量因为被关闭而成为有信号状态,使用返回值减去WAIT_ABANDONED_0得到变为有信号状态的对象在数组中的下标。 WAIT_TIMEOUT:表示超过规定时间。

信号量(Semaphore ) 信号量的用法和互斥的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源。

信号量操作函数(1) 创建信号灯: HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,// 安全属性,NULL表示使用默认的安全描述 LONG lInitialCount, // 初始值 LONG lMaximumCount, // 最大值 LPCTSTR lpName // 名字 ); 打开信号灯: HANDLE OpenSemaphore( DWORD dwDesiredAccess, // 存取方式 BOOL bInheritHandle, // 是否能被继承

信号量操作函数(2) 释放信号灯: BOOL ReleaseSemaphore( HANDLE hSemaphore, // 句柄 LONG lReleaseCount, // 释放数,让信号灯值增加数 LPLONG lpPreviousCount // 用来得到释放前信号灯的值,可以为NULL ); 关闭信号灯: BOOL CloseHandle( HANDLE hObject // 句柄 );

事件 事件,前面讲的信号灯和互斥量可以保证资源被正常的分配和使用,而事件是用来通知其他进程/线程某件操作已经完成。 事件对象可以一两种方式创建,一种为自动重置,在其他线程使用WaitForSingleObject等待到事件对象变为有信号后该事件对象自动又变为无信号状态,一种为人工重置在其他线程使用WaitForSingleObject等待到事件对象变为有信号后该事件对象状态不变。例如有多个线程都在等待一个线程运行结束,我们就可以使用人工重置事件,在被等待的线程结束时设置该事件为有信号状态,这样其他的多个线程对该事件的等待都会成功(因为该事件的状态不会被自动重置)。

事件对象操作函数(1) 创建事件对象: HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性,NULL表示使用默认的安全描述 BOOL bManualReset, // 是否为人工重置 BOOL bInitialState, // 初始状态是否为有信号状态 LPCTSTR lpName // 名字 ); 打开事件对象: HANDLE OpenEvent( DWORD dwDesiredAccess, // 存取方式 BOOL bInheritHandle, // 是否能够被继承

事件对象操作函数(2) 设置事件为无信号状态: BOOL ResetEvent( HANDLE hEvent // 句柄 ); 设置事件有无信号状态: BOOL SetEvent( HANDLE hEvent // 句柄 ); 关闭事件对象: BOOL CloseHandle( HANDLE hObject // 句柄 );