Windows
线程的创建和退出
概念区分
程序:磁盘上的可执行文件(如.exe)
进程:程序执行代码所需资源的集合,不活泼的(状态)
线程:程序执行代码的最小单位,活泼的(状态)
进程为代码执行提供各种各样的资源 本身并不执行代码,由线程进行代码的执行
线程的运行(调度)原理
CPU时间切片:系统将 CPU 的运行时间划分为固定长度的时间片,每个时间片结束时,当前运行的线程会被暂停,然后调度器会选择下一个就绪的线程继续执行
基于CPU时间片方式进行线程调度,就是当只有线程得到CPU的时间片才能执行指令,当线程处于执行的状态,但是却没有分配到时间片,那么就会处于就绪状态,等待系统分配下一个时间片。
保存环境和恢复环境:当线程被切走时,系统会把当前线程的环境保存,当线程再切回来时,恢复环境。
多线程效率与cpu的内核数量和逻辑处理器数量有关 当线程数与逻辑处理器的数量相同时效率最佳 并非线程越多效率越高

线程的创建
线程:
UI线程(主线程):单线程的执行环境,所有的UI控件都必须在主线程上创建和更新,否则会引发跨线程访问的异常(不运行耗时长的任务)
非UI线程(工作线程):处理一些非UI相关的任务,需要自己负责管理线程的生命周期和同步机制,以避免线程间的竞争和死锁(运行耗时长的任务
)
创建一个计数器

将.cpp中用不到的代码删除
保留的代码:
| 12
 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 "framework.h"
 #include "Counter.h"
 
 #define MAX_LOADSTRING 100
 
 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);;
 }
 
 
 
 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:
 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
 {
 EndDialog(hDlg, LOWORD(wParam));
 return (INT_PTR)TRUE;
 }
 break;
 }
 return (INT_PTR)FALSE;
 }
 
 
 | 

创建线程

参数2:分配的栈的大小(给0 为默认的栈大小)
默认栈大小:

线程回调

| 12
 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
 
 | 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:
 {
 HANDLE hThread = CreateThread(NULL, 0, ThreadProc, hDlg, 0,NULL);
 CloseHandle(hThread);
 break;
 }
 case BTN_PAUSE:
 g_bContinue = FALSE;
 break;
 case BTN_CONTINUE:
 g_bContinue = TRUE;
 break;
 case BTN_STOP:
 break;
 default:
 break;
 }
 break;
 case WM_CLOSE:
 EndDialog(hDlg, 0);;
 break;
 }
 return (INT_PTR)FALSE;
 }
 
 | 
回调函数:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | DWORD g_dwCounter = 0;BOOL g_bContinue = TRUE;
 DWORD WINAPI ThreadProc(LPVOID lpParameter) {
 HWND hDlg = (HWND)lpParameter;
 while (true) {
 if (g_bContinue) {
 ++g_dwCounter;
 SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE);
 }
 }
 }
 }
 
 | 
由于暂停时while仍然在执行 使得线程不会停止 cpu的占用不变 用到sleepAPI使得暂停时线程的占用减小

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | DWORD WINAPI ThreadProc(LPVOID lpParameter) {HWND hDlg = (HWND)lpParameter;
 while (true) {
 if (g_bContinue) {
 ++g_dwCounter;
 SetDlgItemInt(hDlg, EDT_COUNTER, g_dwCounter, FALSE);
 }
 else {
 Sleep(1);
 
 }
 }
 }
 
 | 
未暂停:

暂停时:

暂停后counter.exe占用的cpu就大大减少了
线程挂起:不再分配时间切片

恢复:

挂起几次对应的就得恢复几次 线程无法恢复自己(可以挂起自己)
| 12
 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
 
 | 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);
 
 }
 }
 
 
 
 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;
 }
 
 | 
运行结果

线程的退出
退出线程:

| 12
 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
 101
 
 | 
 
 #include "framework.h"
 #include "Counter.h"
 
 #define MAX_LOADSTRING 100
 
 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;
 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:
 CloseHandle(g_hThread);
 g_bStop = TRUE;
 break;
 default:
 break;
 }
 break;
 case WM_CLOSE:
 EndDialog(hDlg, 0);;
 break;
 }
 return (INT_PTR)FALSE;
 }
 
 
 | 
点击开始后会出现类的构造函数

而点击停止后没有析构函数 说明资源没有释放

终止线程:

使用TerminateThread不会释放关键节、堆锁
正常终止线程:
1.线程使用的堆栈等被释放(线程之间有独立的堆栈互不影响)
2.系统将线程对象的退出代码设置为线程的退出码
3.线程内核对象使用计数递减1
4.线程内核对象状态变为已通知
| 12
 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
 
 | 
 
 #include "framework.h"
 #include "Counter.h"
 
 #define MAX_LOADSTRING 100
 
 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;
 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);
 }
 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;
 }
 
 
 | 
面对dll时的情况



点击开始时会显示DLL_THREAD_ATTACH
点击停止时会显示DLL_THREAD_DETACH
终止线程方法
1.线程函数返回(最佳方法)
2.调用ExitThread函数,线程自行撤销(不推荐)
——操作系统清楚该线程使用的所有操作系统资源,但是C++资源(如C++类对象)将不被撤销
3.调用TerminateThread(避免使用)
——拥有线程的进程终止运行之前,系统不撤销线程堆栈
——DLL接不到通知
4.调用TerminateProcess(避免使用)
counter.cpp
| 12
 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
 101
 102
 103
 104
 
 | 
 
 #include "framework.h"
 #include "Counter.h"
 
 #define MAX_LOADSTRING 100
 __declspec(dllexport) void Foo();
 #pragma comment(lib,"./x64/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:
 
 CloseHandle(g_hThread);
 g_bStop = TRUE;
 break;
 default:
 break;
 }
 break;
 case WM_CLOSE:
 ExitThread(0x12345678);
 EndDialog(hDlg, 0);
 break;
 }
 return (INT_PTR)FALSE;
 }
 
 
 | 
dllmain.cpp
| 12
 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
 
 | #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;
 }
 
 
 
 |