一.多道程序设计
1.1 多道程序设计(multiprogramming)
(1)指同时把多个作业放入内存并允许它交替执行,共享系统中的各类资源,当一道程序因某种原因(如I/O请求)而暂停执行时,CPU立即转去执行另一道程序。
(2)会使系统具有多道、宏观上并行、微观上串行的特点,从而有效提高系统的吞吐量和改善资源利用率。
1.2多道程序设计与CPU的利用率
(参见AST-P52)
(1)从概率的角度看CPU的利用率
(2)p:进程等待I/O时间与其停留在内存的时间
(3)n个进程多道执行,则都在等待I/O(此时CPU空闲)的概率是p^n。
(4)CPU的利用率:1-p^n
1.3 多道程序设计下系统特点
(1)执行的并发性
(2)相互的制约性
(3)状态的多变性(动态性)
1.4 并发与并行
(引自百度百科“并发”,百度文库“并发和并行的区别”,《深入理解计算机系统》P488)
(1)Concurrency,逻辑上同时发生
(2)两个或多个事件在同一时间间隔内发生
(3)在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。
(4)一个逻辑流的执行在时间上与另一个流重叠,称为并发流。
(5)X在Y开始之后或结束之前才开始,或Y在X开始之后或结束之前才开始----X和Y互相并发。
二.进程
2.1经典定义:进程是一个执行中的程序实例.(a process is an instance of a program in execution.)
(1)进程是程序的一次运行活动。
(2)进程的运行活动是建立在某个数据集合之上的。
(3)进程在获得资源的基础上从事自己的运行活动。
2.2 所谓“进程”是指一个程序在给定数据集合上的一次执行过程,是系统进行资源分配和运行调度的独立单位。
(1)进程是操作系统对一个正在运行的程序的一种抽象。使得看上去只有这个程序在使用CPU、主存和I/O设备。
(2)进程是计算机科学中最重要和最成功的概念之一。
(3)进程基本上是容纳运行一个程序所需要所有的信息的容器。
(4)一个正在运行的程序的一个实例,它由以下两部分构成。(Jeffrey Richter《Windows核心编程》P67)
①一个内核对象,操作系统用它来管理进程。内核对象也是系统保存进程统计信息的地方。
②一个地址空间,其中包含所有可执行文件或DLL模块的代码和数据。此外,它还包含动态内存分配,比如线程堆栈和堆的分配。
(5)一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。(UNIX标准(特别是IEEE Std 1003.1,2004年版)
2.2 系统中两类进程
(1)系统进程
(2)用户进程
(3)系统进程与用户进程的区别
①系统进程之间的相互关系由操作系统负责协调,以便有利于增加系统的并行性,提高资源的整体利用率;用户进程之间的相互关系要由用户自己(在程序中)安排。
②系统进程直接管理有关的软、硬件资源的活动;用户进程不得插手资源管理。在需要使用某种资源时,必须向系统提出申请,由系统统一调度与分配。
③系统进程级别高于用户进程。
2.3 程序与进程
(1)程序与进程区别
①进程是程序执行,程序是进程的基础;
②程序是静态的,进程是动态的;
③进程与程序不是一一对应的关系;
·一个程序可能启动多次,对应着多个进程。
·一个进程可能会打开多个程序。
④进程有生命期;
⑤进程的并发性;
⑥进程的制约性。
示例:·做蛋糕的食谱:程序;做蛋糕的过程:进程
·上述流程中发生另一个进程:紧急医治(有更高的优先级)
(5)程序三特点
①独占性
②顺序性
③可再现
(6)进程的基本状态
①新建(New)
②运行(Running)
③等待(Waiting)/阻塞(Blocked)
④就绪(Ready)
⑤终止(Terminated)
进程状态变迁图:
2.4 创建进程(AST,P49)
(1)导致进程的创建4种事件
①系统初始化
·前台进程、后台进程
·守护进程(daemon)
②执行了正在运行的进程所调用的进程创建系统调用
③用户请求创建一个新进程
④一个批处理作业的初始化
(2)新进程都是由一个已存在的进程执行了一个用于创建进程的系统调用而创建的。
①Unix、Linux用fork系统调用创建父进程的一个副本,通常再执行execve系统调用,修改其存储映像并运行一个新的程序。
②Windows用CreateProcess处理进程的创建,也负责把正确的程序装入新的进程。Win32有大约100个其它的函数用于处理进程的管理、同步以及相关的事物。
③WINDOWS的EXPLORER进程
Windows程序管理器或者文件资源管理器.用于管理Windows图形壳(shell),包括桌面和文件管理.称为“文件资源管理器”
④CREATEPROCESS的执行进程(引自J.Richter《核心编程》P85)
·系统创建一个进程内核对象,其初始使用计数1。内核对象不是进程本身,是用来管理这个进程的一个小型数据结构。
(使用计数(usage count):内核对象的所有者是操作系统内核,而非进程。其它进程使用这个对象时,则使用计数递增。)
·系统为新进程创建一个虚拟地址空间,并将可执行文件(和所有必要的DLL(DLL是Dynamic Link Library的缩写,意为动态链接库))的代码及数据加载到进程的地址空间。
·为新进程的主线程创建一个线程内核对象(使用计数为1),用于管理这个线程。
·主线程执行C/C++运行时的启动例程,它是由链接器设为应用程序入口的。最终会调用应用程序WinMain,wWinMain,main或wmain函数。
·若系统成功创建了新进程和主线程,CreateProcess将返回TRUE。
⑤示例:CREATEPROCESS(NOTEPAD.EXE)(引自MSDN)
#include <windows.h> #include <stdio.h> void wmain( int argc, WCHAR *argv[] ){ STARTUPINFO si; PROCESS_INFORMATION pi; memset(&si,0,sizeof(si)); si.cb=sizeof(si); memset(&pi,0,sizeof(pi)); if( argc != 2 ){ printf("Usage: %s [cmdline] ", argv[0]); return; } // Start the child process. if( !CreateProcess( NULL, // No module name (use command line) argv[1], // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi ) // Pointer to PROCESS_INFORMATION structure ){ printf( "CreateProcess failed (%d). ", GetLastError() ); return; } /* 添加*/ DWORD priority=GetPriorityClass(pi.hProcess );//进程优先级 HMODULE hModule=GetModuleHandle(NULL);//内存基地址 DWORD CurId=GetCurrentProcessId();//获取当前进程的ID DWORD Pid=pi.dwProcessId ;//创建的进程的ID DWORD Tid=pi.dwThreadId ;//创建的进程的主线程ID // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); }
⑥示例:CREATEPROCESS-STARTUPINFO结构(引自J.Richter《核心编程》P92)
typedef struct _STARTUPINFO{ DWORD cb; //结构字节数,必须 PSTR lpReserved;//保留 PSTR lpDesktop;//在哪个桌面上启动应用程序 PSTR lpTitle;//控制台窗口标题 DWORD dwX; //应用窗口在屏幕的位置(下同) DWORD dwY;// DWORD dwXSize;//应用程序窗口的大小(下同) DWORD dwYSize; DWORD dwXCountChars;//子进程控制台窗口大小 DWORD dwYCountChars; DWORD dwFillattribute;//子进程控制台所用的文本和背景色 DWORD dwFlags; WORD wShowWindow;//应用程序窗口相关 WORD cbReserved2;//保留 PBYTE lpReserved2;//保留 HANDLE hStdInput;//控制台相关句柄(下同) HANDLE hStdOutput; HANDLE hStdError; } STARTUPINFO,*LPSTARTUPINFO;
⑦示例:CREATEPROCESS-PROCESS_INFOMATION结构(引自J.Richter《核心编程》
typedef struct _PROCESS_INFOMATION{ HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION;
说明:
·1 hProcess管理进程内核对象,hThread管理线程内核对象
·2 当CreateProcess在内部打开这些对象时,每个对象的使用计数变为2,这意味着系统要想释放进程对象,进程必须终止(计数减1),且父进程必须调用CloseHandle(计数再减1,变成0),线程同理。
·3 进程ID与线程ID分享同一个号码池。
·4 ID=0,与“System Idle Process”(系统空闲进程)关联,此虚构进程的目的是将其作为Idle线程的占位符,在没有别的线程运行时,系统就运行这个Idle进程。Idle的线程数量等于CPU的数量。
三.进程概述
3.1 进程是计算机科学中最深刻最成功的概念之一
3.2 当我们在一个现代系统上运行一个程序时,会得到一个假象,就好像我们的程序是系统中当前运行着的唯一程序。处理器好像是无间断地一条接一条地执行程序中的指令。代码和数据好像是存储器中唯一的对象。这些假象是通过进程的概念提供给我们的。
3.2 每个程序都是运行在某个进程的上下文(context)中的
上下文是由程序正确运行所需要的状态组成(PC、栈、寄存器、打开的文件等)
3.3 逻辑控制流
一个运行三个进程的系统,处理器的一个物理控制区流分成了三个逻辑流,每个进程一个,交错执行,轮流使用CPU(对应有两个状态,运行态和挂起态),执行时间段叫做时间片(大约50ms)
3.4 示例:进程状态转换
3.5 程序的执行过程
3.6 进程控制块的内容
3.7 典型进程表(进程控制块PCB)的一些字段(P52)
3.8 三个线程的字处理程序
四.需要线程的原因
4.1需要线程的原因
(1)(资源共享)并发实体共享同一个地址空间和所有可用数据的能力。(进程做不到)
(2)(经济)比进程更容易创建、切换和撤销
对于Solaris,进程创建比创建线程慢30倍,进程切换比线程切换慢5倍。
(3)如果存在大量的计算和大量I/O处理,多线程加快应用执行的速度。
响应度高,提高交互能力。
(4)多处理器体系结构的利用。
(5)某个操作可能会陷入长时间等待,等待的线程会进入睡眠状态,无法继续执行,多线程执行可以有效利用等待的时间。典型的例子是等待网络响应,这可能要花费数秒甚至数十秒。
(6)某个操作(常常是计算)会消耗大量的时间,如果只有一个线程,程序和用户之间的交互会中断。多线程可以让一个线程负责交互,另一个线程负责计算。
(7)程序逻辑本身就要求并发操作,例如一个多端下载软件(例如Bittrorrent)。
(8)多CPU或多核计算机(基本就是未来的主流计算机),本身具备同时执行多个线程的能力,因此单线程程序无法全面地发挥计算机的全部计算能力。
(9)相对于多进程应用,多线程在数据共享方面效率要高很多。引自《程序员的自我修养--链接、装载与库》P20
4.2 线程库
(1)为程序员创建和管理线程的API
(2)三种主要线程库
①POSIX Pthread
Pthread作为POSIX标准的扩展,提供用户级或内核级的库。
②Win32
Windows的内核级线程库。
③Java
Java线程API允许线程在Java程序中直接创建和管理。然而,大多数JVM实例运行在宿主操作系统上,Java线程API通常采用宿主系统上的线程库来实现。
4.3 线程(thread)
线程:
一个程序计数器(记录下一条执行指令)
寄存器
一个堆栈
五.线程与进程
5.1 进程与线程
(1)线程必须在某个进程中执行
(2)进程用于把资源集中到一起
(3)线程是在CPU上被调度执行的实体
(4)同一进程中并发运行多个线程。
5.2 并发的进程与线程
(1)多线程共享同个地址空间、打开的文件以及其他资源;
(2)多进程共享物理内存、磁盘、打印机和其他资源。
5.3 进程与线程 引自《Windows核心编程(第5版)》P65
(1)进程是有“惰性”的。进程要做任何事情,都必须让一个线程在它的上下文中运行。该线程负责执行进程地址空间包含的代码。事实上,一个进程可以有多个线程,所有线程都在进程的地址空间中“同时”执行代码。为此,每个线程都有它自己的一组CPU寄存器和它自己的堆栈。每个进程至少要有一个线程来执行进程地址空间包含的代码。当系统创建一个进程的时候,会自动为进程创建第一个线程,这称为主线程(primary thread)。然后,这个线程再创建更多的线程,后者再创建更多的线程……。如果没有线程要执行进程地址空间包含的代码,进程就推动了继续存在的理由。这时,系统会自动销毁进程及其地址空间。
(2)对于所有要运行的线程,操作系统会轮流为每个线程调度一些CPU时间。它会采取循环(round-robin)方式,为每个线程都分配时间片,从而营造出所有线程都在“并发”运行的假象。
(3)
从C程序员的角度
5.4 进程与线程
引自《计算机学科专业基础综合联考辅导教程》(2012版)P373
(1)总论
①线程是进程内的一个执行单元,是比进程更小的执行单位
②一个进程至少有一个线程,可包含多个线程
③线程是进程内一个可调度的实体
④线程是程序(或进程)中相对独立的一个控制流序列
⑤线程是执行的上下文,其含义是执行的现场数据和其他调度所需的信息
⑥线程是进程内一个相对独立的、可调度的执行单元
⑦线程与程序不同的是线程本身不能单独运行,它只能包含在程序中,只能在程序中执行
⑧线程与任何一个程序一样,有一个开始,一系列可执行的命令序列,一个结束。在执行的任何时刻,只有一个执行点。
(2)线程是一个基本的CPU执行单元
①包含一个线程ID、一个程序计数器、一个寄存器组、一个堆栈。
②也有创建、运行、就绪、阻塞和撤销状态。
(3)共享进程的所有资源
①属于同一进程的其他线程共享代码段、数据段,以及其它的操作系统资源(如打开的文件)。
②进程只作为除CPU以外系统资源的分配单位;线程则作为处理机的分配单位。
(4)创建、切换与撤消
①进程创建时,同时也建立第一个线程,用以运行程序,以后在适当时,再建立后续线程。
②线程切换时将运行现场保存到该线程的对应栈区。同一进程的线程切换不会引起进程切换,不同进程的线程切换时,会引起进程的切换。
③进程内所有线程结束时,意味进程结束。
5.5 在WINDOWS中创建进程 《Windows操作系统核心编程实验教程》P7
(1)实验内容:
编写程序,在Windows系统中通过API函数创建一个进程,尽可能多地显示并修改进程的相关信息,最后终止该进程的运行,显示它的创建时间、终止时间等信息
(2)相关API函数
①CreateProcess() 功能:创建一个新进程
②ExitProcess() 功能:终止本进程的运行
③TerminateProcess() 功能:终止一个进程的运行
④GetExitProcess() 功能:获得一个进程的退出码
⑤GetPriorityClass() 功能:显示进程的优先级
⑥SetPriorityClass() 功能:设置一个进程的优先级
⑦FileTimeToSystemTime() 功能:将FileTime类型时间转换为SystemTime
⑧GetProcessWorkingSetSize() 功能:获得进程的内存空间
⑨SetProcessWorkingSetSize( ) 功能:修改进程的内存空间
⑩GetProcessTimes( ) 功能:获得进程的CPU时间