14、Windows API 进程、线程、模块
一、基本概念
1、进程是应用程序的实例。进程包括一个虚拟地址空间及代码、数据、对象等程序运行所需环境和资源的集合。在内存空间中包括若干可执行的代码、数据、资源、一系列对系统对象操作的句柄,安全上下文、进程标识符(PID),环境变量等程序执行的环境。同时,进程还包括一个或多个执行线程。
线程是程序的执行流程。在操作系统层面,线程是需要操作系统为其分配执行时间片的基本单元。线程附属于进程,一个线程可以执行进程中任意部分的代码。一个系统中同一时间只能有少量线程执行(决定于CPU个数和核数),操作系统决定当前执行哪一个线程,并进行调度。每一个线程都包括一个上下文(主要是CPU寄存器值)。在进行线程调度时,系统会保存线程上下文。
一个程序由多个模块组成。程序没有运行时,模块以可执行文件的形式存在(exe、dll等);程序运行后,所需要的模块都加载到进程的虚拟地址空间中,进行初始化的设置后,各模块就可以协同工作。每一个模块都可能包括代码、数据、资源等。
2、可执行文件
程序的载体是可执行文件。可执行文件中包括运行所需的程序、数据及一些配置信息等。Windows平台的可执行文件包括exe、dll、sys等扩展名的文件。
Windows平台的可执行文件基本都是PE格式的。
3、应用程序
应用程序是由一系列具有特定功能、能完成执行操作的可执行文件、数据的集合,一个应用程序可以包括若干个可执行程序、动态链接库、数据文件。Windows平台的应用程序根据与用户交互的方式区分为控制台应用程序与图形用户界面( GUI)程序;编译程序时通过/SUBSYSTE选择。
4、进程
进程提供了程序运行所需要的资源、虚拟内存地址空间、各种数据、可执行的代码、需要使用到的各种内核对象、系统调用接口、优先级与权限配置、工作集、环境变量等,还包括至少一个执行过程(线程)。
进程是正在运行的程序,即程序的运行实例。
每个进程都有一个标识符(PID)和一个句柄,系统和其他进程可以通过PID和进程的句柄对进程进行管理和操作。
5、动态链接库
动态链接库是将应用程序模块化的重要方法。
程序是在进程创建或程序运行时进行链接的,因此称为“动态链接”;静态链接是在程序构建时由链接器进行链接,将代码和数据组织在同一个可执行文件中。
6、模块
每个可执行程序都可以称作一个模块,DLL文件是模块。exe文件也是模块,称为主模块。
7、线程
进程的这种同时处理多个任务的能力是通过线程机制实现的。
线程是附属在进程上的执行实体,是代码的执行流程。
一个进程中可以有多个线程在并发执行。进程的所有线程都共享其虚拟地址空间、数据、系统资源等。每个线程都有自己的栈、上下文(context,包括CPU寄存器值等,线程调度时会进行线程上下文切换)、异常处理程序、调度优先级、标识符等。线程的切换依赖于中断。
每个进程必须有至少一个线程,在进程创建时即开始执行的线程是进程的主线程,主线程可以再创建其他线程。
8、纤程( Fiber)
纤程也是程序执行单元,与线程类似。不同的是纤程必须要应用程序自行调度,而线程是由系统进行调度的。纤程运行于线程的上下文中,一个线程可以调度很多纤程。
9、作业(Job,也称为工作项)
作业是一种对象,可以将一组进程作为一个单元进行管理。作业包括命名对象(namable)、安全对象(securable)和共享对象(sharable),可以控制进程组的属性。
二、进程相关API
Process and Thread Functions
http://msdn.microsoft.com/en-us/library/ms684847%28VS.85%29.aspx
如果进程知道其他进程的标识符( PID),还可以通过OpenProcess函数获取进程的句柄,也可以通过GetProcessId通过句柄获取PID。
创建进程示例
**************************************/
/* 头文件 */
#include <windows.h>
#include <stdio.h>
DWORD CreateChildProcess(LPSTR szChildProcessCmd);
/*************************************
* int main(void)
* 功能 演示进程创建
*
* 参数 未使用
**************************************/
int main()
{
CreateChildProcess("Child.exe abc 123");
}
/*************************************
* DWORD CreateChildProcess(LPSTR szChildProcessCmd)
* 功能 演示创建子进程
*
* 参数 LPSTR szChildProcessCmd 启动子进程的命令行
* 返回值 成功返回,失败返回
**************************************/
DWORD CreateChildProcess(LPSTR szChildProcessCmd)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
// 将启动信息结构清零
ZeroMemory( &si, sizeof(si) );
// 设置结构大小,cb属性应为结构的大小
si.cb = sizeof(si);
// 将进程信息结构清零
ZeroMemory( &pi, sizeof(pi) );
// 创建子进程,并判断是否成功
if( !CreateProcess( NULL, // 使用命令行
szChildProcessCmd, // 命令行
NULL, // 不继承进程句柄
NULL, // 不继承线程句柄
FALSE, // 不继承句柄
0, // 没有创建标志
NULL, // 使用父进程环境变量
NULL, // 使用父进程目录作为当前目录
&si, // STARTUPINFO 结构
&pi ) // PROCESS_INFORMATION 保存相关信息
)
{
// 创建失败
printf( "CreateProcess failed (%d).\n", GetLastError() );
return 1;
}
// 在创建成功后父进程也可直接退出,这里等待子进程执行结束
// 等待子进程结束
// 使用到了通过PROCESS_INFORMATION 返回的相关信息,hProcess为子进程句柄
// 父进程也可以不等待子进程运行完成而直接退出
WaitForSingleObject( pi.hProcess, INFINITE );
// 关闭进程句柄和线程句柄
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return 0;
}
创建线程示例
**************************************/
/* 头文件 */
#include <windows.h>
#include <stdio.h>
/* 常量定义 */
#define MAX_THREADS 5
/* 结构类型 */
typedef struct _THREAD_PARAM {
DWORD i;
DWORD dwRandom;
DWORD dwData;
} THREAD_PARAM, *LPTHREAD_PARAM;
/*************************************
* DWORD WINAPI ThreadProc( LPVOID lpParam )
* 功能 线程函数
* 将参数打印出
*
* 参数 LPVOID lpParam THREAD_PARAM 结构类型
**************************************/
DWORD WINAPI ThreadProc( LPVOID lpParam )
{
LPTHREAD_PARAM pData;
// 参数数据类型
pData = (LPTHREAD_PARAM)lpParam;
// 显示参数
printf("TID = %u,\t Parameters = %u, %u, %u\n",
GetCurrentThreadId(),
pData->i, pData->dwRandom, pData->dwData);
// 释放保存参数的内存(在主线程中分配的).
HeapFree(GetProcessHeap(), 0, pData);
return 0;
}
/*************************************
* void main()
* 功能 主线程函数,创建了多个线程
**************************************/
void main()
{
LPTHREAD_PARAM pData;
DWORD dwThreadId[MAX_THREADS];
HANDLE hThread[MAX_THREADS];
int i;
// 创建MAX_THREADS 个线程.
for( i=0; i<MAX_THREADS; i++ )
{
// 为线程函数参数分配内存
pData = (LPTHREAD_PARAM)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(THREAD_PARAM));
if( pData == NULL )
{
printf("HeapAlloc error;\n");
ExitProcess(2);
}
// 设置参数
pData->i = i;
pData->dwRandom = rand();
pData->dwData = 100;
// 创建线程
hThread[i] = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
ThreadProc, // 线程函数
pData, // 参数
0, // 默认创建标志
&dwThreadId[i]); // 返回TID
// 判断是否创建成功
if (hThread[i] == NULL)
{
ExitProcess(i);
}
}
}
三、进程状态信息
两类API:
进程状态帮助(Process Status Helper,PSAPI),工具帮助(Tool helper)两类API。
PSAPI:
http://msdn.microsoft.com/en-us/library/ms684884%28VS.85%29.aspx
Tool helpr API:
http://msdn.microsoft.com/en-us/library/ms686832%28VS.85%29.aspx
Dynamic-Link Library Functions
http://msdn.microsoft.com/en-us/library/ms682599%28VS.85%29.aspx
导出dll有两种方法:
一是在函数声明是使用__declspec(dllexport)关键字;
二是在模块定义文件(.def)中进行说明。
参考
[1] 精通Windows API