一、进程
1.基本概念
1)进程是一个容器,包含程序执行所需要的代码、数据、资源等信息。Windows是多任务操作系统,可以同时执行多个进程。
2)进程的特点
A.每个进程都有自己唯一的标识号——PID。
B.每个进程都有自己的安全属性。
C.每个进程都有自己的地址空间,进程之间不能互相访问的地址空间。
D.每个进程至少包含一个线程。
2.进程环境(进程上下文)
1)获取环境块
LPTCH GetEnvironmentStrings (void)
Name1=Value1\0Name2=Value2\0...NameN=ValueN\0\0
成功返回进程环境块指针,失败返回NULL。
2)释放环境块
BOOL FreeEnvironmentStrings (
LPTCH lpszEnvironmentBlock // 进程环境块指针
);
成功返回TRUE,失败返回FALSE。
3)设置环境变量
BOOL SetEnvironmentVariable (
LPCTSTR lpName, // 变量名
LPCTSTR lpValue, // 变量值
);
成功返回TRUE,失败返回FALSE。
4)获取环境变量
DWORD GetEnvironmentVariable (
LPCTSTR lpName, // 变量名
LPTSTR lpBuffer, // 变量值缓冲区
DWORD nSize // 变量值缓冲区大小(以字符为单位,含结尾空字符)
);
成功返回实际变量值字符串长度,失败返回0。
3.进程信息
1)获取进程ID
DWORD GetCurrentProcessId (void);
返回调用进程的ID。
2)获取进程句柄
HANDLE GetCurrentProccess (void);
返回调用进程的伪句柄,用于后续函数调用。
4.创建进程
1)WinExec - Win16遗留,现在基本不用
2)ShellExecute - Shell操作,速度慢
3)CreateProcess - 使用最多
BOOL CreateProcess (
LPCTSTR lpApplicationName, // 可执行程序路径
LPTSTR lpComandLine, // 命令行参数
... // 进程安全属性,NULL
... // 线程安全属性,NULL
BOOL bInheritHandles, // 子进程是否可以继承父进程的句柄
DWORD dwCreationFlags, // 创建方式,0表示立即启动
LPVOID lpEnvironment, // 子进程环境,NULL表示继承父进程环境
LPCTSTR lpCurrentDirectory, // 子进程工作目录,NULL表示继承父进程
// 工作目录
LPSTARTUPINFO lpStartupInfo, // 启动信息
LPPROCESS_INFORMATION lpProcessInformation // 进程信息(输出)
);
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 子进程句柄
HANDLE hThread; // 子进程的主线程句柄
DWORD dwProcessId; // 子进程ID
DWORD dwThreadId; // 子进程的主线程ID
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
成功返回TRUE,失败返回FALSE。
5.等候进程
DWORD WaitForSingleObject (
HANDLE hHandle, // 句柄
DWORD dwMilliseconds // 等候时间(毫秒),INFINITE永远等候
);
成功返回引起该函数返回的事件码,失败返回WAIT_FAILED(-1)
引起该函数返回的事件码:
WAIT_OBJECT_0 - 句柄有信号
WAIT_TIMEOUT - 超时
6.退出进程
VOID ExitProcess (
UINT uExitCode // 退出码
);
7.终止进程
BOOL TerminateProcess (
HANDLE hProcess, // 进程句柄
UINT uExitCode // 退出码
);
成功返回TRUE,失败返回FALSE。
8.通过进程ID获取句柄
HANDLE OpenProcess (
DWORD dwDesireAccess, // 访问权限,PROCESS_ALL_ACCESS
BOOL bInheritHandle, // 子进程是否继承此函数所返回的句柄
DWORD dwProcessId // 进程ID
);
成功返回对应给定进程ID的进程句柄,失败返回NULL。
二、线程
1.基本概念
1)线程是可以执行的代码实例。系统以线程为单位调度程序。一个程序可以包含多个线程,实现多任务。
2)线程的特点
A.每个线程都有自己的唯一标识——TID。
B.每个线程都有自己的安全属性。
C.每个线程都有自己的内存堆栈。
void foo (void) {
static int a = 10;
a++;
}
D.每个线程都有自己的寄存器信息。
c = a + b;
3)进程多任务和线程多任务
A.系统中的多个进程地址空间独立,彼此交换数据困难。
B.一个进程中的多个线程地址空间共享,彼此交换数据方便,容易产生冲突。
4)线程调度:将CPU的执行时间划分成若干时间片,分配给不同的线程。操作系统根据时间片的分配,轮流执行不同的线程。
2.线程过程函数
DWORD WINAPI ThreadProc (
LPVOID lpParameter // 线程参数
);
返回值代表线程执行的成功或失败,可由GetExitCodeThread函数获得。
3.创建线程
HANDLE CreateThread (
... // 安全属性,NULL
SIZE_T dwStackSize, // 线程栈的初始字节数,0表示与调用线程相同
LPTHREAD_START_ROUTINE lpStartAddress, // 线程过程函数地址
LPVOID lpParameter, // 线程参数
DWORD dwCreationFlags, // 创建方式
LPDWORD lpThreadId // 线程ID(输出)
);
成功返回线程句柄,失败返回NULL。
dwCreationFlags取值:
0 - 立即运行
CREATE_SUSPENDED - 创建后先挂起,直到调用ResumeThread函数再运行
4.退出线程
VOID ExitThread (
DWORD dwExitCode // 退出码
);
5.终止线程
BOOL TerminateThread (
HANDLE hThread, // 线程句柄
DWORD dwExitCode // 退出码
);
成功返回TRUE,失败返回FALSE。
6.挂起线程
DWORD SuspendThread (
HANDLE hThread // 线程句柄
);
成功返回线程此前被挂起的次数,失败返回-1。
7.恢复线程
DWORD ResumeThread (
HANDLE hThread // 线程句柄
);
成功返回线程此前被恢复的次数,失败返回-1。
8.获取线程ID
DWORD GetCurrentThreadId (VOID);
返回调用线程的ID。
9.获取线程句柄
HANDLE GetCurrentThread (VOID);
返回调用线程的句柄。
10.通过线程ID获取句柄
HANDLE OpenThread (
DWORD dwDesireAccess, // 访问权限,THREAD_ALL_ACCESS
BOOL bInheritHandle, // 子进程是否继承此函数所返回的句柄
DWORD dwThreadId // 线程ID
);
成功返回对应给定线程ID的线程句柄,失败返回NULL。
11.关闭线程句柄
CloseHandle (hThread);
三、线程同步
1.原子锁(Interlocked)
S1: g_cn -> 寄存器
S2: 寄存器的值+1
S3: 寄存器 -> g_cn
g_cn 0
I
0 -> 寄存器 - 寄存器里值0
寄存器的值+1 - 寄存器里值1 -> 备份
II
0 -> 寄存器 - 寄存器里值0
寄存器的值+1 - 寄存器里值1
1 -> g_cn - g_cn 1
++
++
++
++
g_cn 5
I
1 -> g_cn - g_cn 1
1)原子自增
LONG InterlockedIncrement (
LPLONG lpAddress // 自增变量地址
);
返回自增以后的结果。
2)原子自减
LONG InterlockedDecrement (
LPLONG lpAddress // 自减变量地址
);
返回自减以后的结果。
2.临界区(Critical Section)
CRITICAL_SECTION - 临界区结构体
1)初始临界区
VOID InitializeCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
2)进入临界区
VOID EnterScriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
阻塞,直到调用线程获得对指定临界区对象的所有权才返回。任何时候只有一个线程拥有临界区对象的所有权。
3)离开临界区
VOID LeaveCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
4)删除临界区
VOID DeleteCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
3.互斥体(Mutex)
1)创建互斥体
HANDLE CreateMutex (
... // 安全属性,NULL
BOOL bInitialOwner, // 调用线程是否初始拥有该互斥体
LPCTSTR lpMame // 互斥体名字
);
成功返回互斥体句柄,失败返回NULL。
2)等待互斥体
WaitForSingleObject (hMutex, INFINITE);
若其它线程拥有该互斥体,则hMutex无信号,函数阻塞,直到调用线程获得对该互斥体的所有权,此时hMutex有信号,函数返回。
3)释放互斥体
BOOL ReleaseMutex (
HANDLE hMutex // 互斥体句柄
);
成功返回TRUE, 失败返回FALSE。
4)关闭互斥体
CloseHandle (hMutex);
4.信号量(Semaphore)
1)创建信号量
HANDLE CreateSemaphore (
... // 安全属性,NULL
LONG lInitialCount, // 初始资源计数
LONG lMaximumCount, // 最大资源计数
LPCTSTR lpName // 信号量名称
);
成功返回信号量句柄,失败返回NULL。
2)等待信号量
WaitForSingleObject (hSemaphore, INFINITE);
若资源计数为0,则hSemaphore无信号,函数阻塞,直到资源计数大于0,此时hSemaphore有信号,函数返回,同时资源计数减1。
3)释放信号量
BOOL ReleaseSemaphore (
HANDLE hSemaphore, // 信号量句柄
LONG lReleaseCount, // 资源计数增量
LPLONG lpPreviousCount // 此前资源计数,可为NULL
);
成功返回TRUE,失败返回FALSE。4)关闭信号量
Cl
oseHandle (hSemaphore);
5.线程局部存储
局部与线程的全局变量。
1)分配线程局部存储
DWORD TlsAlloc (VOID);
成功返回线程局部存储索引,失败返回-1。
2)保存数据到线程局部存储
BOOL TlsSetValue (
DWORD dwTlsIndex, // 线程局部存储索引
LPVOID lpTlsValue // 数据
);
成功返回TRUE,失败返回FALSE。
3)从线程局部存储中获取数据
LPVOID TlsGetValue (
DWORD dwTlsIndex // 线程局部存储索引
);
成功返回线程局部存储中的数据,失败返回NULL。
4)释放线程局部存储
BOOL TlsFree (
DWORD dwTlsIndex // 线程局部存储索引
);
成功返回TRUE,失败返回FALSE。
5)静态线程局部存储
__declspec (thread) int g_cn = 0;
__declspec (thread) static int s_cn = 0;
1.基本概念
1)进程是一个容器,包含程序执行所需要的代码、数据、资源等信息。Windows是多任务操作系统,可以同时执行多个进程。
2)进程的特点
A.每个进程都有自己唯一的标识号——PID。
B.每个进程都有自己的安全属性。
C.每个进程都有自己的地址空间,进程之间不能互相访问的地址空间。
D.每个进程至少包含一个线程。
2.进程环境(进程上下文)
1)获取环境块
LPTCH GetEnvironmentStrings (void)
Name1=Value1\0Name2=Value2\0...NameN=ValueN\0\0
成功返回进程环境块指针,失败返回NULL。
2)释放环境块
BOOL FreeEnvironmentStrings (
LPTCH lpszEnvironmentBlock // 进程环境块指针
);
成功返回TRUE,失败返回FALSE。
3)设置环境变量
BOOL SetEnvironmentVariable (
LPCTSTR lpName, // 变量名
LPCTSTR lpValue, // 变量值
);
成功返回TRUE,失败返回FALSE。
4)获取环境变量
DWORD GetEnvironmentVariable (
LPCTSTR lpName, // 变量名
LPTSTR lpBuffer, // 变量值缓冲区
DWORD nSize // 变量值缓冲区大小(以字符为单位,含结尾空字符)
);
成功返回实际变量值字符串长度,失败返回0。
3.进程信息
1)获取进程ID
DWORD GetCurrentProcessId (void);
返回调用进程的ID。
2)获取进程句柄
HANDLE GetCurrentProccess (void);
返回调用进程的伪句柄,用于后续函数调用。
4.创建进程
1)WinExec - Win16遗留,现在基本不用
2)ShellExecute - Shell操作,速度慢
3)CreateProcess - 使用最多
BOOL CreateProcess (
LPCTSTR lpApplicationName, // 可执行程序路径
LPTSTR lpComandLine, // 命令行参数
... // 进程安全属性,NULL
... // 线程安全属性,NULL
BOOL bInheritHandles, // 子进程是否可以继承父进程的句柄
DWORD dwCreationFlags, // 创建方式,0表示立即启动
LPVOID lpEnvironment, // 子进程环境,NULL表示继承父进程环境
LPCTSTR lpCurrentDirectory, // 子进程工作目录,NULL表示继承父进程
// 工作目录
LPSTARTUPINFO lpStartupInfo, // 启动信息
LPPROCESS_INFORMATION lpProcessInformation // 进程信息(输出)
);
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; // 子进程句柄
HANDLE hThread; // 子进程的主线程句柄
DWORD dwProcessId; // 子进程ID
DWORD dwThreadId; // 子进程的主线程ID
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
成功返回TRUE,失败返回FALSE。
5.等候进程
DWORD WaitForSingleObject (
HANDLE hHandle, // 句柄
DWORD dwMilliseconds // 等候时间(毫秒),INFINITE永远等候
);
成功返回引起该函数返回的事件码,失败返回WAIT_FAILED(-1)
引起该函数返回的事件码:
WAIT_OBJECT_0 - 句柄有信号
WAIT_TIMEOUT - 超时
6.退出进程
VOID ExitProcess (
UINT uExitCode // 退出码
);
7.终止进程
BOOL TerminateProcess (
HANDLE hProcess, // 进程句柄
UINT uExitCode // 退出码
);
成功返回TRUE,失败返回FALSE。
8.通过进程ID获取句柄
HANDLE OpenProcess (
DWORD dwDesireAccess, // 访问权限,PROCESS_ALL_ACCESS
BOOL bInheritHandle, // 子进程是否继承此函数所返回的句柄
DWORD dwProcessId // 进程ID
);
成功返回对应给定进程ID的进程句柄,失败返回NULL。
二、线程
1.基本概念
1)线程是可以执行的代码实例。系统以线程为单位调度程序。一个程序可以包含多个线程,实现多任务。
2)线程的特点
A.每个线程都有自己的唯一标识——TID。
B.每个线程都有自己的安全属性。
C.每个线程都有自己的内存堆栈。
void foo (void) {
static int a = 10;
a++;
}
D.每个线程都有自己的寄存器信息。
c = a + b;
3)进程多任务和线程多任务
A.系统中的多个进程地址空间独立,彼此交换数据困难。
B.一个进程中的多个线程地址空间共享,彼此交换数据方便,容易产生冲突。
4)线程调度:将CPU的执行时间划分成若干时间片,分配给不同的线程。操作系统根据时间片的分配,轮流执行不同的线程。
2.线程过程函数
DWORD WINAPI ThreadProc (
LPVOID lpParameter // 线程参数
);
返回值代表线程执行的成功或失败,可由GetExitCodeThread函数获得。
3.创建线程
HANDLE CreateThread (
... // 安全属性,NULL
SIZE_T dwStackSize, // 线程栈的初始字节数,0表示与调用线程相同
LPTHREAD_START_ROUTINE lpStartAddress, // 线程过程函数地址
LPVOID lpParameter, // 线程参数
DWORD dwCreationFlags, // 创建方式
LPDWORD lpThreadId // 线程ID(输出)
);
成功返回线程句柄,失败返回NULL。
dwCreationFlags取值:
0 - 立即运行
CREATE_SUSPENDED - 创建后先挂起,直到调用ResumeThread函数再运行
4.退出线程
VOID ExitThread (
DWORD dwExitCode // 退出码
);
5.终止线程
BOOL TerminateThread (
HANDLE hThread, // 线程句柄
DWORD dwExitCode // 退出码
);
成功返回TRUE,失败返回FALSE。
6.挂起线程
DWORD SuspendThread (
HANDLE hThread // 线程句柄
);
成功返回线程此前被挂起的次数,失败返回-1。
7.恢复线程
DWORD ResumeThread (
HANDLE hThread // 线程句柄
);
成功返回线程此前被恢复的次数,失败返回-1。
8.获取线程ID
DWORD GetCurrentThreadId (VOID);
返回调用线程的ID。
9.获取线程句柄
HANDLE GetCurrentThread (VOID);
返回调用线程的句柄。
10.通过线程ID获取句柄
HANDLE OpenThread (
DWORD dwDesireAccess, // 访问权限,THREAD_ALL_ACCESS
BOOL bInheritHandle, // 子进程是否继承此函数所返回的句柄
DWORD dwThreadId // 线程ID
);
成功返回对应给定线程ID的线程句柄,失败返回NULL。
11.关闭线程句柄
CloseHandle (hThread);
三、线程同步
1.原子锁(Interlocked)
S1: g_cn -> 寄存器
S2: 寄存器的值+1
S3: 寄存器 -> g_cn
g_cn 0
I
0 -> 寄存器 - 寄存器里值0
寄存器的值+1 - 寄存器里值1 -> 备份
II
0 -> 寄存器 - 寄存器里值0
寄存器的值+1 - 寄存器里值1
1 -> g_cn - g_cn 1
++
++
++
++
g_cn 5
I
1 -> g_cn - g_cn 1
1)原子自增
LONG InterlockedIncrement (
LPLONG lpAddress // 自增变量地址
);
返回自增以后的结果。
2)原子自减
LONG InterlockedDecrement (
LPLONG lpAddress // 自减变量地址
);
返回自减以后的结果。
2.临界区(Critical Section)
CRITICAL_SECTION - 临界区结构体
1)初始临界区
VOID InitializeCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
2)进入临界区
VOID EnterScriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
阻塞,直到调用线程获得对指定临界区对象的所有权才返回。任何时候只有一个线程拥有临界区对象的所有权。
3)离开临界区
VOID LeaveCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
4)删除临界区
VOID DeleteCriticalSection (
LPCRITICAL_SECTION lpCriticalSection // 临界区结构体地址
);
3.互斥体(Mutex)
1)创建互斥体
HANDLE CreateMutex (
... // 安全属性,NULL
BOOL bInitialOwner, // 调用线程是否初始拥有该互斥体
LPCTSTR lpMame // 互斥体名字
);
成功返回互斥体句柄,失败返回NULL。
2)等待互斥体
WaitForSingleObject (hMutex, INFINITE);
若其它线程拥有该互斥体,则hMutex无信号,函数阻塞,直到调用线程获得对该互斥体的所有权,此时hMutex有信号,函数返回。
3)释放互斥体
BOOL ReleaseMutex (
HANDLE hMutex // 互斥体句柄
);
成功返回TRUE, 失败返回FALSE。
4)关闭互斥体
CloseHandle (hMutex);
4.信号量(Semaphore)
1)创建信号量
HANDLE CreateSemaphore (
... // 安全属性,NULL
LONG lInitialCount, // 初始资源计数
LONG lMaximumCount, // 最大资源计数
LPCTSTR lpName // 信号量名称
);
成功返回信号量句柄,失败返回NULL。
2)等待信号量
WaitForSingleObject (hSemaphore, INFINITE);
若资源计数为0,则hSemaphore无信号,函数阻塞,直到资源计数大于0,此时hSemaphore有信号,函数返回,同时资源计数减1。
3)释放信号量
BOOL ReleaseSemaphore (
HANDLE hSemaphore, // 信号量句柄
LONG lReleaseCount, // 资源计数增量
LPLONG lpPreviousCount // 此前资源计数,可为NULL
);
成功返回TRUE,失败返回FALSE。4)关闭信号量
Cl
oseHandle (hSemaphore);
5.线程局部存储
局部与线程的全局变量。
1)分配线程局部存储
DWORD TlsAlloc (VOID);
成功返回线程局部存储索引,失败返回-1。
2)保存数据到线程局部存储
BOOL TlsSetValue (
DWORD dwTlsIndex, // 线程局部存储索引
LPVOID lpTlsValue // 数据
);
成功返回TRUE,失败返回FALSE。
3)从线程局部存储中获取数据
LPVOID TlsGetValue (
DWORD dwTlsIndex // 线程局部存储索引
);
成功返回线程局部存储中的数据,失败返回NULL。
4)释放线程局部存储
BOOL TlsFree (
DWORD dwTlsIndex // 线程局部存储索引
);
成功返回TRUE,失败返回FALSE。
5)静态线程局部存储
__declspec (thread) int g_cn = 0;
__declspec (thread) static int s_cn = 0;