《C++多线程编程实战》——2.3 解释进程模型

2.3 解释进程模型

传统的操作系统必须提供创建进程和终止进程的方法。下面列出了4个引发创建进程的主要事件:

系统初始化;
正在运行的进程执行创建进程的系统调用;
用户要求创建新进程;
启动批处理作业。
操作系统启动后,会创建多个进程。一些是前台进程,与用户(人)交互,并根据用户的要求执行操作。一些是后台进程,执行特定的功能,与用户行为不相关。例如,可以把接收电子邮件设计成后台进程,因为大部分时间都用不到这一功能,只需在有电子邮件到达时处理即可。后台进程通常处理诸如电子邮件、打印等活动。

在Windows中,CreateProcess(一个Win32函数调用)负责创建进程和加载进程上下文。欲详细了解CreateProcess,请参阅MSDN(http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx)。我们将在下面的示例中演示基本的进程创建和同步。

准备就绪
确定安装并运行了Visual Studio。

操作步骤
现在,我们按下面的步骤创建一个程序,稍后再详细解释。

1. 创建一个新的默认C++控制台应用程序,名为ProcessDemo

2. 打开ProcessDemo.cpp

3. 添加下面的代码:

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
  STARTUPINFO startupInfo = { 0 };
  PROCESS_INFORMATION processInformation = { 0 };

  BOOL bSuccess = CreateProcess(
    TEXT("C:\\Windows\\notepad.exe"), NULL, NULL,
    NULL, FALSE, NULL, NULL, NULL, &startupInfo,
    &processInformation);

  if (bSuccess)
  {
    cout << "Process started." << endl
       << "Process ID:\t"
       << processInformation.dwProcessId << endl;
  }
  else
  {
    cout << "Cannot start process!" << endl
       << "Error code:\t" << GetLastError() << endl;
  }

  return system("pause");
}```
该程序的输出如图2.4所示:

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/5f5a99c8dfdc5b6ea1df2f5a23fa8317f31bad94.png" >
</div>

图2.4

如图2.4所示,开始了一个新的进程(记事本)。

示例分析
`CreateProcess`函数用于创建一个新进程及其主线程。新进程在主调进程的安全上下文中运行。

操作系统为进程分配进程标识符。进程标识符用于标识进程,在进程终止之前有效。或者,对于一些API(如`OpenProcess`函数),进程标识符用于获得进程的句柄。最初线程的线程标识符由进程分配,该标识符可用于在`OpenThread`中打开一个线程的句柄。线程标识符在线程终止之前有效,可作为系统中线程的唯一标识。这些标识符都返回`PROCESS_INFORMATION`结构中。

主调线程可以使用`WaitForInputIdle`函数,在新进程完成其初始化且正在等待用户输入时等待。这在父进程和子进程的同步中很有用,因为`CreateProcess`不会等到新进程完成初始化才返回。例如,创建的进程会在查找与新进程相关的窗口之前使用`WaitForInputIdle`函数。

终止进程较好的做法是调用`ExitProcess`函数,因为它会给所属进程的所有DLL都发送一条即将终止的通知。而关闭进程的其他方法就不会这样做(如,`TerminateProcessAPI`)。注意,只要进程中有一个线程调用`ExitProcess`函数,该进程的其他线程都会立即终止,根本没机会执行其他代码(包括相关DLL的线程终止代码)。

更多讨论
虽然每个进程都是一个独立的实体,有各自的指令指针和内部状态,但是进程之间也要经常交互。一个进程生成的输出数据可能是另一个进程所需的输入数据。根据两个进程的相对运行速度,可能会发生这种情况:读操作已准备运行,但是却没有输入。在能读到输入数据之前,该进程必定被阻塞。从逻辑上看,如果进程被阻塞就不能继续运行,因为该进程正在等待尚未获得的输入。如果操作系统在这时决定把CPU暂时分配给另一个进程,正在等待的进程就有可能停止。这是两种完全不同的情况。第一种情况是问题本身造成的(即,在用户键入数据之前无法解析用户的命令行);而第二种情况是系统的技术原因造成的(即,进程用完了分配给它的时间,又没有足够的CUP能单独运行该线程)。

图2.5中的状态图演示了一个进程可能处于的3种状态。

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/27e7d713e4cf9c5de3d2b758ac39a9cd48be8ccd.png" >
</div>

图2.5 进程的三种状态

运行:此时,该进程正在使用CPU。
就绪:该进程可运行,但是它暂时停止让其他进程运行。
阻塞:在某些外部事件发生前,该进程不能运行。
运行和就绪状态有些类似。处于这两种状态的进程都可以运行,只是在就绪状态中,进程暂时没有CPU可用。阻塞状态与前两种状态不同,在阻塞状态中,即使CPU空闲,进程也不能运行。

假设有进程A。当调度器选择另一个进程在CPU上执行时,进程A发生转换过程2。当调度器选择执行进程A时,发生转换过程3。为了等待输入,转换过程1把进程A设置为阻塞状态。当进程A获得所需的输入时,发生转换过程4。
时间: 2024-08-02 03:28:53

《C++多线程编程实战》——2.3 解释进程模型的相关文章

《C++多线程编程实战》——.7 线程模型的实现

2.7 线程模型的实现 我们可以把进程看作是一个对象,它的任务就是把相关资源分组.每个进程都有一个地址空间,如图2.10所示. 图2.10 进程的地址空间 这个所谓的进程图像必须在初始化CreateProcess时加载至物理内存中.所有的资源(如文件句柄.子进程的信息.信号处理器等)都被储存起来.把它们以进程的形式分组在一起,更容易管理. 除进程外,还有一个重要的概念是线程.线程是CPU可执行调度的最小单位.也就是说,进程本身不能获得CPU时间,只有它的线程才可以.线程通过它的工作变量和栈来储存

《C++多线程编程实战》——第2章 进程和线程的概念2.1 简介

第2章 进程和线程的概念 C++多线程编程实战本章介绍以下内容: 进程和线程解释进程模型进程的实现进程间通信(IPC)解决典型的IPC问题线程模型的实现线程的用法在用户空间实现线程在内核实现线程 2.1 简介 现在的计算机能同时处理多件事,许多Windows用户还没有完全意识到这一点.我们举例说明一下.当启动PC系统时,许多进程都在后台启动(例如,管理电子邮件的进程.负责更新病毒库的进程等).通常,用户在执行其他任务时(如,上网),还会打印文件或播放CD.这些活动都需要管理.支持多进程的多任务系

《C++多线程编程实战》——第1章 C++概念和特性简介1.1 介绍

第1章 C++概念和特性简介 C++多线程编程实战 本章介绍以下内容: 创建一个C++项目 程序结构.执行流.运行时对象 结构编程方法 理解面向对象编程方法 解释继承.重载和覆盖 理解多态 事件处理器和消息传递接口 链表.队列.栈示例 1.1 介绍 系统所执行的程序的进程或抽象是所有操作系统的核心概念.现在,绝大多数的操作系统在同一时间内都可以进行多项操作.例如,计算机在用户编辑Word文档时,还可以打印该文档.从硬盘缓冲区读数据.播放音乐等.在多任务操作系统中,中央处理单元(CPU)在程序中快

《C++多线程编程实战》导读

前言 C++多线程编程实战多线程编程正逐渐成为IT行业和开发人员关注的焦点.开发商希望开发出用户友好.界面丰富,而且能并发执行的应用程序.强大的C++语言和本地Win32 API特性为多线程编程提供了良好开端.有了强大的C++,可以轻松地创建不同类型的应用程序,执行并行,而且还能优化现有的工作. 本书是一本实践为主.通俗易懂的Windows多线程编程指导.你将学到如何从多线程方案中受益,增强你的开发能力,构建更好的应用程序.本书不仅讲解了创建并行代码时遇到的问题,而且还帮助读者详细理解同步技术.

Java多线程编程实战之不提倡的方法

不提倡使用的方法是为支持向后兼容性而保留的那些方法,它们在以后的版本中可能出现,也可能不出现.Java 多线程支持在版本 1.1 和版本 1.2 中做了重大修订,stop().suspend() 和 resume() 函数已不提倡使用.这些函数在 JVM 中可能引入微妙的错误.虽然函数名可能听起来很诱人,但请抵制诱惑不要使用它们. 调试线程化的程序 在线程化的程序中,可能发生的某些常见而讨厌的情况是死锁.活锁.内存损坏和资源耗尽. 死锁 死锁可能是多线程程序最常见的问题.当一个线程需要一个资源而

《JAVA多线程编程实战指南》之Two-phase Termination(两阶段终止)模式

本文是<JAVA多线程编程实战指南>的样章,感谢作者授权并发网(ifeve.com)发表此文.感谢demochen整理此文. 5.1Two-phase Termination模式简介 停止线程是一个目标简单而实现却不那么简单的任务.首先,Java没有提供直接的API用于停止线程.此外,停止线程还有一些额外的细节需要考虑,如停止的线程处于阻塞(如等待锁)或者等待状态(等待其他线程),尚有未处理完的任务等. Two-phase Termination模式通过将停止线程这个动作分解为准备阶段和执行阶

《C++多线程编程实战》——1.6 解释继承、重载和覆盖

1.6 解释继承.重载和覆盖 继承是OOP中非常重要的特性.继承至少关系到两个类(或更多类):如果B类是某一种A类,那么B类的对象就拥有与A类对象相同的属性.除此之外,B类也可以实现新的方法和属性,以代替A类相应的方法和属性. 准备就绪 确定安装并运行了Visual Studio. 操作步骤 现在,执行以下步骤来修改前面的示例. 1.创建一个默认控制台应用程序,命名为InheritanceTest. 2.打开InheritanceTest.cpp文件,输入下面的代码: #include "std

《C++多线程编程实战》——2.2 进程和线程

2.2 进程和线程 图2.1演示了执行4个程序调度的一个单核CPU多任务处理系统.图2.2演示了执行4个进程的一个多核CPU多任务处理系统,每个进程单独运行,各有一个控制流. 图2.1 单核CPU多任务处理系统 图2.2 多核CPU多任务处理系统 如图2.3所示,随着时间的推移,虽然进程有不同程度的进展,但是在每一时刻,单核CPU只运行一个进程. 图2.3 进程在单核CPU中的运行情况 前面提到过,在传统的操作系统中,每个进程都有一个地址空间和一个控制线程.在许多情况下,一个进程的地址空间中要执

《C++多线程编程实战》——2.4 进程的实现

2.4 进程的实现 在现代的多任务系统中,进程控制块(Process Control Block,PCB)储存了高效管理进程所需的许多不同数据项.PCB是操作系统为了管理进程,在内核中设置的一种的数据结构.操作系统中的进程用PCB来表示.虽然这种数据结构的细节因系统而异,但是常见的部分大致可分为三大类: 进程标识数据:进程状态数据:进程控制数据. 图2.6 PCB是管理进程的中心.绝大多数操作系统程序(包括那些与调度.内存.I/O资源访问和性能监控相关的程序)都要访问和修改它.通常,要根据PCB