线程的创建和退出
概念区分
- 程序-磁盘上的可执行文件
- 进程-程序执行代码所需资源的集合,不活泼的,懒惰的
- 线程-程序执行代码的最小单位,活泼的,勤奋的
线程的运行(调度)原理
cpu时间切片
线程的创建
UI线程(主线程)-一般不做繁重的任务
非UI线程(工作线程)-一般做较繁重的任务
新建Windows桌面应用程序
设计Dialog
示例编辑框的ID为EDT_COUNTER
四个按钮的ID分别为BTN_START、BTN_PAUSE、BTN_STOP、BTN_CONTINUE
Sleep函数可以在暂停的时候减少线程对CPU的占用
暂停线程SuspendThread
恢复线程ResumeThread
一个线程无法自己恢复自己,但是可以自己把自己挂起
Counter.cpp
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 75 76 77 78 79 80 81
|
#include "framework.h" #include "Counter.h"
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { return (int)DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), NULL, About); }
DWORD g_dwCounter = 0; BOOL g_bContinue = TRUE; HANDLE g_hThread = NULL;
DWORD WINAPI ThreadProc(LPVOID lpParameter) { HWND hDlg = (HWND)lpParameter; while (true) { ++g_dwCounter; SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE); #if 0 if (g_bContinue) { ++g_dwCounter; SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE); } else { Sleep(1); } #endif
} }
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) { case BTN_START: { g_hThread = CreateThread(NULL, 0, ThreadProc, hDlg, 0, NULL); break; } case BTN_PAUSE: SuspendThread(g_hThread); break; case BTN_CONTINUE: ResumeThread(g_hThread); break; case BTN_STOP: break; default: break; } break;
case WM_CLOSE: EndDialog(hDlg, 0); break; } return (INT_PTR)FALSE; }
|
运行后回弹出一个计数器窗口,点击开始就会开始计数,点击暂停会停止计数,点击继续又会重新计数
线程的退出
1 2 3 4 5 6 7 8 9 10 11 12
| BOOL b_bStop = TRUE;
DWORD WINAPI ThreadProc(LPVOID lpParameter) { HWND hDlg = (HWND)lpParameter; while (!b_bStop) { ++g_dwCounter; SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE); } return 0; }
|
1 2 3 4
| case BTN_STOP: CloseHandle(g_hThread); b_bStop = TRUE; break;
|
运行后点击停止可以退出进程
退出进程:ExitThread
重命名
TerminateThread也可以结束线程
新建类
1 2 3 4 5 6
| class CFoo { public: CFoo() { MessageBox(NULL, "CFoo()", NULL, MB_OK); } ~CFoo() { MessageBox(NULL, "~CFoo()", NULL, MB_OK); } };
|
1 2 3 4 5
| DWORD WINAPI ThreadProc(LPVOID lpParameter) { CFoo foo; HWND hDlg = (HWND)lpParameter; }
|
新建动态链接库
dllmain.cpp
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
| #include "pch.h"
__declspec(dllexport)void Foo() { MessageBox(NULL, "Foo Called", NULL, MB_OK); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: OutputDebugString("Dll1 DLL_PROCESS_ATTACH"); break; case DLL_THREAD_ATTACH: OutputDebugString("Dll1 DLL_THREAD_ATTACH"); break; case DLL_THREAD_DETACH: OutputDebugString("Dll1 DLL_THREAD_DETACH"); break; case DLL_PROCESS_DETACH: OutputDebugString("Dll1 DLL_PROCESS_DETACH"); break; } return TRUE; }
|
Counter.cpp完整代码
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
#include "framework.h" #include "Counter.h" __declspec(dllimport)void Foo(); #pragma comment(lib,"./Debug/Dll1.lib")
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { Foo(); return (int)DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), NULL, About); }
DWORD g_dwCounter = 0; BOOL g_bContinue = TRUE; HANDLE g_hThread = NULL; BOOL g_bStop = TRUE;
class CFoo { public: CFoo() { MessageBox(NULL, "CFoo()", NULL, MB_OK); } ~CFoo() { MessageBox(NULL, "~CFoo()", NULL, MB_OK); } }; DWORD WINAPI ThreadProc(LPVOID lpParameter) { CFoo foo; HWND hDlg = (HWND)lpParameter; while (TRUE) { if (g_bStop) { ExitThread(0x1234); }
++g_dwCounter; SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE); #if 0 if (g_bContinue) { ++g_dwCounter; SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE); } else { Sleep(1); } #endif } return 0; }
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) { case BTN_START: { g_bStop = FALSE; g_hThread = CreateThread(NULL, 0, ThreadProc, hDlg, 0, NULL); break; } case BTN_PAUSE: SuspendThread(g_hThread); break; case BTN_CONTINUE: ResumeThread(g_hThread); break; case BTN_STOP: TerminateThread(g_hThread, 0x123456); CloseHandle(g_hThread); break; default: break; } break;
case WM_CLOSE: EndDialog(hDlg, 0); break; } return (INT_PTR)FALSE; }
|
运行Counter.exe时会显示DLL_PROCESS_ATTACH,点击开始时会显示DLL_THREAD_ATTACH,点击停止时会显示DLL_THREAD_DETACH,关掉Counter.exe会显示DLL_PROCESS_DETACH