线程的创建和退出

概念区分

  • 程序-磁盘上的可执行文件
  • 进程-程序执行代码所需资源的集合,不活泼的,懒惰的
  • 线程-程序执行代码的最小单位,活泼的,勤奋的

线程的运行(调度)原理

cpu时间切片

线程的创建

UI线程(主线程)-一般不做繁重的任务

非UI线程(工作线程)-一般做较繁重的任务

新建Windows桌面应用程序

image-20240711152942907

设计Dialog

image-20240711153922486

示例编辑框的ID为EDT_COUNTER

四个按钮的ID分别为BTN_START、BTN_PAUSE、BTN_STOP、BTN_CONTINUE

image-20240711154622175

image-20240711154642460

Sleep函数可以在暂停的时候减少线程对CPU的占用

image-20240711160124112

暂停线程SuspendThread

image-20240711161318219

恢复线程ResumeThread

image-20240711161351342

一个线程无法自己恢复自己,但是可以自己把自己挂起

image-20240711162319334

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
// Counter.cpp : 定义应用程序的入口点。
//

#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 // 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_hThread = CreateThread(NULL, 0, ThreadProc, hDlg, 0, NULL);
break;
}
case BTN_PAUSE:
//g_bContinue = FALSE;
SuspendThread(g_hThread);
break;
case BTN_CONTINUE:
//g_bContinue = TRUE;
ResumeThread(g_hThread);
break;
case BTN_STOP:
break;
default:
break;
}
break;

case WM_CLOSE:
EndDialog(hDlg, 0);
break;
}
return (INT_PTR)FALSE;
}

运行后回弹出一个计数器窗口,点击开始就会开始计数,点击暂停会停止计数,点击继续又会重新计数

image-20240711164152840

线程的退出

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

image-20240711171053524

重命名

image-20240711171305038

TerminateThread也可以结束线程

image-20240711172157771

新建类

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;
}

新建动态链接库

image-20240711174239469

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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#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
// Counter.cpp : 定义应用程序的入口点。
//

#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 // 0
}
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:
//g_bContinue = FALSE;
SuspendThread(g_hThread);
break;
case BTN_CONTINUE:
//g_bContinue = TRUE;
ResumeThread(g_hThread);
break;
case BTN_STOP:
TerminateThread(g_hThread, 0x123456);
CloseHandle(g_hThread);
//g_bStop = TRUE;
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

image-20240712150707609

image-20240711175444102