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

简介:

本节书摘来自异步社区出版社《C++多线程编程实战》一书中的第2章,第2.4节,作者: 【黑山共和国】Milos Ljumovic(米洛斯 留莫维奇),更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.4 进程的实现

在现代的多任务系统中,进程控制块(Process Control Block,PCB)储存了高效管理进程所需的许多不同数据项。PCB是操作系统为了管理进程,在内核中设置的一种的数据结构。操作系统中的进程用PCB来表示。虽然这种数据结构的细节因系统而异,但是常见的部分大致可分为三大类:

进程标识数据;
进程状态数据;
进程控制数据。


ee860636f354f494a5f5e605f59ec0a692026c97

图2.6 

PCB是管理进程的中心。绝大多数操作系统程序(包括那些与调度、内存、I/O资源访问和性能监控相关的程序)都要访问和修改它。通常,要根据PCB为进程构建数据。例如,某PCB内指向其他PCB的指针以不同的调度状态(就绪、阻塞等)创建进程队列。

操作系统必须代表进程来管理资源。它必须不断地关注每个进程的状态、系统资源和内部值。下面的程序示例演示了如何获得一个进程基本信息结构地址,其中的一个特征就是PCB的地址。另一个特征是唯一的进程ID。为简化示例,我们只输出从对象中读取的进程ID。

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

操作步骤
我们再来创建一个操控进程的程序。这次,我们从进程基本信息结构中获取进程ID。请执行以下步骤。

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

2. 打开NtProcessDemo.cpp

3. 添加下面的代码:

#include "stdafx.h"
#include <Windows.h>
#include <Winternl.h>
#include <iostream>

using namespace std;

typedef NTSTATUS(NTAPI* QEURYINFORMATIONPROCESS)(
  IN HANDLE ProcessHandle,
  IN PROCESSINFOCLASS ProcessInformationClass,
  OUT PVOID ProcessInformation,
  IN ULONG ProcessInformationLength,
  OUT PULONG ReturnLength OPTIONAL
  );

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;
    PROCESS_BASIC_INFORMATION pbi;
    ULONG uLength = 0;

    HMODULE hDll = LoadLibrary(
      TEXT("C:\\Windows\\System32\\ntdll.dll"));

    if (hDll)
    {
      QEURYINFORMATIONPROCESS QueryInformationProcess =
        (QEURYINFORMATIONPROCESS)GetProcAddress(
        hDll, "NtQueryInformationProcess");

      if (QueryInformationProcess)
      {
        NTSTATUS ntStatus = QueryInformationProcess(
          processInformation.hProcess,
          PROCESSINFOCLASS::ProcessBasicInformation,
          &pbi, sizeof(pbi), &uLength);

        if (NT_SUCCESS(ntStatus))
        {
          cout << "Process ID (from PCB):\t"
            << pbi.UniqueProcessId << endl;
        }
        else
        {
          cout << "Cannot open PCB!" << endl
            << "Error code:\t" << GetLastError()
            << endl;
        }
      }
      else
      {
        cout << "Cannot get "
          << "NtQueryInformationProcess function!"
          << endl << "Error code:\t"
          << GetLastError() << endl;
      }
      FreeLibrary(hDll);
    }
    else
    {
      cout << "Cannot load ntdll.dll!" << endl
        << "Error code:\t" << GetLastError() << endl;
    }
  }
  else
  {
    cout << "Cannot start process!" << endl
      << "Error code:\t" << GetLastError() << endl;
  }
  return 0;
}```
示例分析
该例中,我们使用了一些其他头文件:`Winternl.h`和`Windows.h`。`Winternl.h`头文件包含了大部分Windows内部函数的原型和数据表示,例如`PROCESS_BASIC_INFORMATION`结构的定义:

typedef struct _PROCESS_BASIC_INFORMATION {
  PVOID Reserved1;
  PPEB PebBaseAddress;
  PVOID Reserved2[2];
  ULONG_PTR UniqueProcessId;
  PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;`
操作系统在调用内核态和用户态之间的子例程时会用到该结构。

结合PROCESSINFOCLASS::ProcessBasicInformation枚举,我们通过UniqueProcessId特征获取进程标识符,如上面的代码所示。

首先,定义QEURYINFORMATIONPROCESS,这是从ntdll.dll中加载的NtQueryInformationProcess函数的别名。当通过GetProcAddressWin32 API获得该函数的地址时,就可以询问PROCESS_BASIC_INFORMATION对象了。注意PROCESS_BASIC_INFORMATION结构的PebBaseAddress字段是一个指针,指向新创建进程的PCB。如果还想进一步研究PCB,检查新创建的进程,则必须在运行时使用ReadProcessMemory例程。因为PebBaseAddress指向属于新创建进程的内存。

相关文章
|
15天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
30天前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
58 0
|
存储 安全 算法
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
64 5
|
1月前
|
消息中间件 存储 算法
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
82 0
|
14天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
38 6
|
1月前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
67 0
|
1天前
|
Java 数据库连接 数据处理
Python从入门到精通:3.1.2多线程与多进程编程
Python从入门到精通:3.1.2多线程与多进程编程
|
8天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
28 0
|
23天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
30天前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
73 0

相关实验场景

更多