内核对象
一、内核对象是什么?
- 内核对象本质上是一个结构体,但是这个结构体只能由操作系统内核部分进行访问,并且只能由它进行创建,如果用于想要操作一个内核对象,就必须通过句柄找到内核对象,并且使用相应的API进行访问。
- 内核对象的通用操作形式:创建内核对象:CreateXXX,打开一个内核对象 OpenXXX,关闭内核对象一般会使用到 CloseHandle()。
二、内核对象的特性
- 全局性:内核对象是跨进程的,可以在不同进程中访问同一个对象,通常使用字符串或ID标识一个对象。
- 引用计数:每一个内核对象都有一个引用计数,当创建或者打开一个内核对象的时候,引用计数会+1,当关闭一个内核对象的时候,引用计数会-1,当引用计数为0时,内核对象会被销毁。
- 安全性:大多数内核对象在创建的时候,都需要设置一个安全属性,安全属性描述了哪些用户可以以什么样的方式访问内核对象,目前通常使用NULL来填充这个字段。
- 句柄表:每一个进程都有一个句柄表,相同的内核对象在不同的进程中,可能句柄值是不一样的,通常句柄值是句柄表的下标左移两位(4的倍数),句柄表描述了内核对象所在的位置以及访问需要用到的权限。一个进程退出的时候,会主动将句柄表中的内核对象计数-1 。
| 句柄值 |
内核对象的地址 |
打开的方式 |
| [1] * 4 |
文件 0x80001000 |
创建了文件 test1.txt |
| [2] * 4 |
文件0x80002000 |
打开了 test2.txt |
| 句柄值 |
内核对象的地址 |
打开的方式 |
| [1] * 4 |
文件 0x80002000 |
创建了文件 test2.txt |
| [2] * 4 |
文件 0x80001000 |
打开了 test1.txt |
| [3] * 4 |
文件 0x80001000 |
打开了 test1.txt |
三、 内核对象的跨进程访问
- 由父进程继承给子进程
- 通过内核对象的ID或字符串名称打开内核对象
- 使用 DuplicateHandle() 函数在进程间传递内核对象
四、 在句柄表中添加内核对象的方式
- 创建一个内核对象
- 打开一个内核对象
- 从父进程继承内核对象(子进程本身并不知道自己继承了父进程的内核对象)
- 使用 DuplicateHandle() 拷贝内核对象
进程和模块
一、 什么是进程?
进程可以看作是一个运行中的程序,应该由一个可执行程序(.exe)产生。一个进程最少包含了一个进程内核对象、一个线程内核对象(执行代码)、一块虚拟地址空间(4GB)、需要用到的数据和代码(模块)
二、什么是模块?
windows下的可执行文件(.dll .exe)通常被称作模块,用于提供必须的数据以及代码。
在 VS 中: 程序断下来后 -> 菜单 -> 调试 -> 窗口 -> 模块
三、 退出进程的方式
- 通过main()\WinMain() 主动的进程退出
- 通过 ExitProcess 函数退出
- 通过 TerminateProcess 函数强制结束
进程操作
创建进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <iostream> #include <windows.h>
int main(int argc, char*argv[]) { PROCESS_INFORMATION ProcessInfomation = { 0 };
STARTUPINFO StartupInfo = { sizeof(STARTUPINFO) };
CreateProcess( L"C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &StartupInfo, &ProcessInfomation ); CloseHandle(ProcessInfomation.hThread); CloseHandle(ProcessInfomation.hProcess);
system("start notepad.exe");
return 0; }
|
操作进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <windows.h>
int main() {
HWND hWnd = FindWindow(NULL, L"无标题 - 记事本");
DWORD Pid = 0; GetWindowThreadProcessId(hWnd, &Pid);
HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, Pid);
TerminateProcess(Process, -1); CloseHandle(Process);
ExitProcess(-1);
return 0; }
|
遍历进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include <iostream> #include <string> #include <windows.h> using namespace std;
#include <TlHelp32.h>
int main() { wstring buffer;
HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
PROCESSENTRY32 ProcessInfo = { sizeof(PROCESSENTRY32) };
if (Process32First(Snapshot, &ProcessInfo)) { do { buffer += ProcessInfo.szExeFile; buffer += '\n';
{ DWORD PathSize = MAX_PATH; WCHAR ImagePath[MAX_PATH] = { 0 };
HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessInfo.th32ProcessID);
QueryFullProcessImageName(Process, 0, ImagePath, &PathSize);
CloseHandle(Process); buffer += '\t'; buffer += ImagePath; buffer += '\n'; }
} while (Process32Next(Snapshot, &ProcessInfo)); }
printf("%ls\n", buffer.c_str()); return 0; }
|
遍历模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <iostream> #include <windows.h>
#include <TlHelp32.h>
int main() { HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 10536);
MODULEENTRY32 ModuleInfo = { sizeof(MODULEENTRY32) };
if (Module32First(Snapshot, &ModuleInfo)) { do { printf("%ls\n", ModuleInfo.szExePath);
} while (Module32Next(Snapshot, &ModuleInfo)); }
return 0; }
|
文件操作
无句柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include <iostream> #include <windows.h>
int main() { RemoveDirectory(L"E:\\123");
WIN32_FILE_ATTRIBUTE_DATA FileInfo = { 0 }; GetFileAttributesEx(L"E:\\新建文件夹", GetFileExInfoStandard, &FileInfo);
FILETIME LocalTime = { 0 }; FileTimeToLocalFileTime(&FileInfo.ftCreationTime, &LocalTime); SYSTEMTIME System = { 0 }; FileTimeToSystemTime(&LocalTime, &System);
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) printf("目录 "); else printf("文件 "); printf("%s\n", FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ? "隐藏" : "显示");
return 0; }
|
有句柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <iostream> #include <windows.h>
int main() { HANDLE Handle = CreateFileA( "E:\\abc.txt", GENERIC_ALL, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE Handle = CreateFileA( "E:\\abc.txt", GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD RealWrite = 0; WriteFile(Handle, "123456", 3, &RealWrite, NULL);
SetFilePointer(Handle, 0, NULL, FILE_BEGIN); DWORD Current = SetFilePointer(Handle, 0, NULL, FILE_CURRENT); DWORD RealRead = 0; CHAR Buffer[10] = { 0 }; ReadFile(Handle, Buffer, 3, &RealRead, NULL);
SetFilePointer(Handle, 2, NULL, FILE_BEGIN); SetEndOfFile(Handle);
LARGE_INTEGER size; size.LowPart = GetFileSize(Handle, (LPDWORD)&size.HighPart);
return 0; }
|
文件遍历
例子1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <iostream> #include <windows.h>
void EnumFile(LPCSTR DirPath, int level) { CHAR Path[MAX_PATH] = { 0 }; sprintf(Path, "%s\\*", DirPath);
WIN32_FIND_DATAA FindData = { 0 };
HANDLE FindHandle = FindFirstFileA(Path, &FindData);
if (FindHandle != INVALID_HANDLE_VALUE) { do { if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strcmp(FindData.cFileName, ".") && strcmp(FindData.cFileName, "..")) { printf("%*s目录: %s\n", level, "", FindData.cFileName); CHAR NextPath[MAX_PATH] = { 0 }; sprintf(NextPath, "%s\\%s", DirPath, FindData.cFileName); EnumFile(NextPath, level + 1); } } else { printf("%*s文件: %s\n", level, "", FindData.cFileName); } } while (FindNextFileA(FindHandle, &FindData)); }
FindClose(FindHandle); }
int main() { EnumFile("D:\\", 1);
return 0; }
|
例子2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| void CMyDlg2::EnumFile(CString filePath) { i = 0; j = 0; dwConstSize1 = 0; dwConstSize2 = 0; CString cs; CString fullPath = filePath + L"\\*"; WIN32_FIND_DATA fileData = {}; HANDLE hFile = FindFirstFile(fullPath, &fileData); if (hFile != INVALID_HANDLE_VALUE) { do { if (wcscmp(fileData.cFileName, L".") == 0 || wcscmp(fileData.cFileName, L"..") == 0) continue;
if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { EnumFile(filePath + L"\\" + fileData.cFileName); continue; } m_FileList.InsertItem(i, filePath + L"\\" + fileData.cFileName); DWORD dwSize = (fileData.nFileSizeHigh * (MAXDWORD + 1)) + fileData.nFileSizeLow; cs.Format(L"%d kb", dwSize/1024); m_FileList.SetItemText(i, 1, cs); if (wcscmp(L".exe", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".obj", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".tlog", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".idb", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".pdb", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".pch", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".res", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".ilk", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".sdf", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".ipch", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".log", PathFindExtension(fileData.cFileName)) == 0 || wcscmp(L".lastbuildstate", PathFindExtension(fileData.cFileName)) == 0 ) { CString csPath; csPath.Format(L"%s\\%s" , filePath,fileData.cFileName); path.push_back(csPath); m_FileList2.InsertItem(i, filePath + L"\\" + fileData.cFileName); m_FileList2.SetItemText(i, 1, cs); dwConstSize2 += dwSize / 1024; j ++; } dwConstSize1 += dwSize / 1024; i++; } while (FindNextFile(hFile, &fileData)); } }
|
进程间通讯
WM_COPYDATA
使用WM_COPYDATA进行通信
使用 WM_COPYDATA 要求接受端必须是一个窗口程序
发送端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> #include <windows.h>
int main() { HWND hWnd = FindWindowA(NULL, "Window1");
COPYDATASTRUCT Data = { 0 }; Data.cbData = 6; Data.lpData = (LPVOID)"hello"; Data.dwData = 0x12345678;
SendMessage(hWnd, WM_COPYDATA, NULL, (LPARAM)&Data);
return 0; }
|
接收端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_COPYDATA: { COPYDATASTRUCT* CopyData = (COPYDATASTRUCT*)lParam; MessageBoxA(NULL, (LPCSTR)CopyData->lpData, (LPCSTR)CopyData->lpData, MB_OK); } } return DefWindowProc(hWnd, message, wParam, lParam); }
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { WNDCLASS WndClass = { 0 }; WndClass.lpszMenuName = NULL; WndClass.lpfnWndProc = WndProc; WndClass.hInstance = hInstance; WndClass.lpszClassName = L"Window"; WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.cbClsExtra = WndClass.cbWndExtra = 0; WndClass.hCursor = LoadCursor(nullptr, IDC_ARROW); WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClass(&WndClass);
HWND hWnd = CreateWindowW(L"Window", L"Window1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);
MSG msg = { 0 }; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
|
邮槽mailslot
使用mailslot进行通信
邮槽只能用于单向通信,但是可以在局域网内进行通信
发送端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <windows.h>
int main() { // 1. 打开邮槽对象 HANDLE hFile = CreateFile( L"\\\\.\\mailslot\\Sample", // 邮槽名称 GENERIC_WRITE, // 读写属性 FILE_SHARE_READ, // 共享属性 NULL, // 安全属性 OPEN_EXISTING, // 打开方式 FILE_ATTRIBUTE_NORMAL, // 标志位 NULL); // 文件模板(默认留空)
// 2. 向mailslot写入 DWORD dwWritten = 0; LPCSTR lpMessage = "邮槽测试消息!"; DWORD dwMegLen = strlen(lpMessage) + sizeof(CHAR); WriteFile(hFile, lpMessage, dwMegLen, &dwWritten, NULL);
// 3. 结束 printf("已经向邮槽写入信息!\n"); CloseHandle(hFile);
return 0; }
|
接收端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <iostream> #include <windows.h>
int main() { HANDLE hSlot = CreateMailslot( L"\\\\.\\mailslot\\Sample", 0, MAILSLOT_WAIT_FOREVER, NULL);
while (true) {
DWORD dwMsgCount = 0, dwMsgSize = 0;
GetMailslotInfo( hSlot, NULL, &dwMsgSize, &dwMsgCount, NULL);
if (dwMsgSize == MAILSLOT_NO_MESSAGE) { Sleep(2000); continue; }
while (dwMsgCount) { PBYTE lpBuffer = new BYTE[dwMsgSize]{ 0 };
DWORD dwRet = 0; if (!ReadFile(hSlot, lpBuffer, dwMsgSize, &dwRet, NULL)) { printf("ReadFile函数执行失败,错误码:%d.\n", GetLastError()); delete[] lpBuffer; return 0; }
printf("邮槽的内容: %s\n", lpBuffer);
GetMailslotInfo(hSlot, (LPDWORD)NULL, &dwMsgSize, &dwMsgCount, nullptr); delete[] lpBuffer; }
} return 0; }
|
线程操作
创建线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <iostream> #include <windows.h>
DWORD WINAPI WorkerThread(LPVOID lpThreadParameter) { LPCSTR Str = (LPCSTR)lpThreadParameter;
while (TRUE) { printf("WorkerThread: %s\n", Str); Sleep(1000); }
return 0; }
int main() { HANDLE Thread = CreateThread( NULL, NULL, WorkerThread, (LPVOID)"15pb", NULL, NULL);
while (TRUE) { printf("MainThread\n"); Sleep(1000); }
WaitForSingleObject(Thread, INFINITY);
return 0; }
|
等待线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include <iostream> #include <windows.h>
DWORD WINAPI WorkerThread(LPVOID lpThreadParameter) { LPCSTR Str = (LPCSTR)lpThreadParameter;
for (int i = 0; i < 100; ++i) { printf("WorkerThread: [%d]%s\n", i, Str); }
return 0; }
int main() {
HANDLE Thread = CreateThread( NULL, NULL, WorkerThread, (LPVOID)"15pb", NULL, NULL);
printf("MainThread\n");
if (Thread != NULL) WaitForSingleObject(Thread, INFINITE);
return 0; }
|
遍历线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <windows.h>
#include <TlHelp32.h>
int main() { HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
THREADENTRY32 ThreadInfo = { sizeof(THREADENTRY32) };
if (Thread32First(Snapshot, &ThreadInfo)) { do {
if (ThreadInfo.th32OwnerProcessID == 4936) { printf("TID: %d\n", ThreadInfo.th32ThreadID); }
} while (Thread32Next(Snapshot, &ThreadInfo)); }
return 0; }
|
挂起恢复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <iostream> #include <windows.h>
#include <TlHelp32.h>
int main() { HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
THREADENTRY32 ThreadInfo = { sizeof(THREADENTRY32) };
if (Thread32First(Snapshot, &ThreadInfo)) { do {
if (ThreadInfo.th32OwnerProcessID == 5028) { HANDLE Thread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ThreadInfo.th32ThreadID);
ResumeThread(Thread); TerminateThread(Thread, -1);
CloseHandle(Thread); }
} while (Thread32Next(Snapshot, &ThreadInfo)); }
return 0; }
|
使用伪句柄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include <iostream> #include <windows.h>
void GetThreadCreateTime(HANDLE Thread) { FILETIME CreateTime = { 0 }, UserTime = { 0 }; FILETIME KernelTime = { 0 }, ExitTime = { 0 };
GetThreadTimes(Thread, &CreateTime, &ExitTime, &KernelTime, &UserTime);
FILETIME LocalTime = { 0 }; FileTimeToLocalFileTime(&CreateTime, &LocalTime); SYSTEMTIME SystemTime = { 0 }; FileTimeToSystemTime(&LocalTime, &SystemTime);
printf("%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒\n", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond); }
DWORD WINAPI WorkerThread(LPVOID lpThreadParameter) { HANDLE MainThread = (HANDLE)lpThreadParameter;
GetThreadCreateTime(MainThread);
return 0; }
int main() { HANDLE MainThread = GetCurrentThread();
GetThreadCreateTime(MainThread);
Sleep(2000);
HANDLE Thread = CreateThread(NULL, NULL, WorkerThread, (LPVOID)MainThread, NULL, NULL);
WaitForSingleObject(Thread, INFINITE);
return 0; }
|
伪句柄转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <iostream> #include <windows.h>
void GetThreadCreateTime(HANDLE Thread) { FILETIME CreateTime = { 0 }, UserTime = { 0 }; FILETIME KernelTime = { 0 }, ExitTime = { 0 };
GetThreadTimes(Thread, &CreateTime, &ExitTime, &KernelTime, &UserTime);
FILETIME LocalTime = { 0 }; FileTimeToLocalFileTime(&CreateTime, &LocalTime); SYSTEMTIME SystemTime = { 0 }; FileTimeToSystemTime(&LocalTime, &SystemTime);
printf("%d 年 %d 月 %d 日 %d 时 %d 分 %d 秒\n", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond); }
DWORD WINAPI WorkerThread(LPVOID lpThreadParameter) { HANDLE MainThread = (HANDLE)lpThreadParameter;
GetThreadCreateTime(MainThread);
return 0; }
int main() { HANDLE MainThread = GetCurrentThread();
GetThreadCreateTime(MainThread);
HANDLE RealHandle = NULL; DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &RealHandle, 0, false, DUPLICATE_SAME_ACCESS);
Sleep(2000);
HANDLE Thread = CreateThread(NULL, NULL, WorkerThread, (LPVOID)RealHandle, NULL, NULL);
WaitForSingleObject(Thread, INFINITE);
return 0; }
|
线程环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <iostream> #include <windows.h>
int main() { CONTEXT stcCxt = { CONTEXT_FULL }; if (!GetThreadContext(GetCurrentThread(), &stcCxt)) return false;
if (!SetThreadContext(GetCurrentThread(), &stcCxt)) return false;
return 0; }
|
线程同步
多线程问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <stdio.h> #include <windows.h>
// 全局变量,同时被多个线程访问 int Number = 0;
// 同步: 多个线程需要按照某种顺序执行 // 互斥: 多个线程操作(读写)同一个资源,不在意顺序
// 异步: 执行一件事情的时候,可以做其他事情,通常依赖函数[无论有没有完成都先返回] _kbhit() // 同步: 执行一件事情的时候,必须等他完成(阻塞,等待函数的返回值)
// 线程函数1 DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { // 将全局变量 Number 自增十万次 for (int i = 0; i < 100000; i++) { Number++; }
return 0; }
// 线程函数2 DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { // 将全局变量 Number 自增十万次 for (int i = 0; i < 100000; i++) { Number++; }
return 0; }
int main() { HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL); // 等待两个线程同时执行结束 WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1); // 输出全局变量 printf("%d", Number);
return 0; }
// Number++ 一条指令被转换成了3条汇编指令(非原子操作)
// mov eax, dword ptr[Number] [0]: Number(0) // add eax, 1 [0]: Number(0) eax(1) // mov dword ptr[Number],eax [0]: Number(1)
// mov eax, dword ptr[Number] [1]: Number(1) // add eax, 1 [1]: Number(1) eax(2) // mov dword ptr[Number],eax [1]: Number(2)
// mov eax, dword ptr[Number] [0]: Number(2) // add eax, 1 [0]: Number(2) eax(3) -----------
// mov eax, dword ptr[Number] [1]: Number(2) // add eax, 1 [1]: Number(2) eax(3) // mov dword ptr[Number],eax [1]: Number(3)
// mov eax, dword ptr[Number] [0]: Number(3) // add eax, 1 [1]: Number(3) eax(4) // mov dword ptr[Number],eax [1]: Number(4)
// mov dword ptr[Number],eax [0]: Number(3) -----------
|
原子操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| -#include <stdio.h> #include <windows.h>
long Number = 0;
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { InterlockedIncrement(&Number);
}
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { InterlockedIncrement(&Number); }
return 0; }
int main() { HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1);
return 0; }
|
临界区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <stdio.h> #include <windows.h>
long Number = 0;
CRITICAL_SECTION CriticalSection = { 0 };
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) {
EnterCriticalSection(&CriticalSection); Number++; LeaveCriticalSection(&CriticalSection); }
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { EnterCriticalSection(&CriticalSection); Number++; LeaveCriticalSection(&CriticalSection); }
return 0; }
int main() { InitializeCriticalSection(&CriticalSection);
HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1);
DeleteCriticalSection(&CriticalSection);
return 0; }
|
等待函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <iostream> #include <windows.h>
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 1000; ++i) { printf("WorkerThreadAAA: %d\n", i); }
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 200; ++i) { printf("WorkerThreadBBB: %d\n", i); }
return 0; }
int main() { HANDLE ThreadHandles[2] = { 0 };
ThreadHandles[0] = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); ThreadHandles[1] = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForMultipleObjects(2, ThreadHandles, FALSE, INFINITE);
return 0; }
|
互斥体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| #include <stdio.h> #include <windows.h>
HANDLE Mutex = CreateMutex(NULL, FALSE, L"Mutex");
long Number = 0;
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Mutex, INFINITE); Number++; ReleaseMutex(Mutex); }
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Mutex, INFINITE); Number++; ReleaseMutex(Mutex); }
return 0; }
int main() { HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1);
return 0; }
|
事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <stdio.h> #include <windows.h>
HANDLE Event = CreateEvent(NULL, TRUE, TRUE, NULL);
long Number = 0;
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Event, INFINITE); Number++; SetEvent(Event); }
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Event, INFINITE); Number++; SetEvent(Event); }
return 0; }
int main() { HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1);
return 0; }
|
信号量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <stdio.h> #include <windows.h>
HANDLE Semaphore = CreateSemaphore(NULL, 1, 1, NULL);
long Number = 0;
DWORD WINAPI WorkerThreadA(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Semaphore, INFINITE); Number++;
LONG Count = 0; ReleaseSemaphore(Semaphore, 1, &Count); }
return 0; }
DWORD WINAPI WorkerThreadB(LPVOID lpThreadParameter) { for (int i = 0; i < 100000; i++) { WaitForSingleObject(Semaphore, INFINITE); Number++; LONG Count = 0; ReleaseSemaphore(Semaphore, 1, &Count); }
return 0; }
int main() { HANDLE hThread1 = CreateThread(NULL, NULL, WorkerThreadA, NULL, NULL, NULL); HANDLE hThread2 = CreateThread(NULL, NULL, WorkerThreadB, NULL, NULL, NULL);
WaitForSingleObject(hThread1, -1); WaitForSingleObject(hThread2, -1);
return 0; }
|