Win32编程之线程开发(八)

一、线程概念

(1).Windows线程是可以执行的代码的实例,系统是以线程为单位调度程序,一个程序当中可以有多个线程,实现多任务的处理

(2).Windows线程的特点:

  • 线程都具有一个ID
  • 每个线程都具有自己的内存栈
  • 同一进程中的线程使用同一个地址空间

(3).线程的调度:操作系统将CPU的执行时间划分成时间片,依次根据时间片执行不同的线程,线程轮询:线程A->线程B->线程A...

二、线程的使用

1.创建线程

1
2
3
4
5
6
7
8
9
HANDLE WINAPI CreateThread(
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //安全属性
    _In_ SIZE_T dwStackSize, //线程栈的大小
    _In_ LPTHREAD_START_ROUTINE lpStartAddress, //线程处理函数的函数地址
    _In_opt_ __drv_aliasesMem LPVOID lpParameter, //传递给线程处理函数的参数
    _In_ DWORD dwCreationFlags, //线程的创建方式
    _Out_opt_ LPDWORD lpThreadId //创建成功,返回线程的ID
);
创建成功,返回线程句柄

2.定义线程处理函数 

1
2
3
DWORD WINAPI ThreadProc(
    LPVOID lpParameter //创建线程时,传递给线程的参数
);

示例代码:

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 <Windows.h>
#include <iostream>
 
using namespace std;
 
DWORD CALLBACK ThreadProc(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        cout << szText << endl;
        Sleep(1000);
    }
 
    return 0;
}
 
int main() {
    const char* pszText = "********";
    DWORD nID = 0;
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)pszText, 0, &nID);
    if (hThread == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    system("pause");
 
    return 1;
}

三、线程的挂起和唤醒

(1).线程的挂起

1
2
3
DWORD SuspendThread(
    HANDLE hThread //handle to thread  
);

(2).线程的唤醒 

1
2
3
DWORD ResumenThread(
    HANDLE hThread //handle to thread
);

示例代码: 

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 <Windows.h>
#include <iostream>
 
using namespace std;
 
DWORD CALLBACK ThreadProc(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        cout << szText << endl;
        Sleep(1000);
    }
 
    return 0;
}
 
DWORD CALLBACK ThreadProc1(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        cout << szText << endl;
        Sleep(1000);
    }
 
    return 0;
}
 
int main() {
    const char* pszText = "********";
    DWORD nID = 0;
    //线程立即执行
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)pszText, 0, &nID);
    if (hThread == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    const char* pszText1 = "--------";
    DWORD nID1 = 0;
    //线程挂起
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, (LPVOID)pszText1, CREATE_SUSPENDED, &nID1);
    if (hThread1 == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    getchar();
    SuspendThread(hThread);
    ResumeThread(hThread1);
    getchar();
 
    return 1;
}

四、线程的销毁

(1).结束指定线程

1
2
3
4
BOOL TerminateThread(
    HANDLE hThread, //handle to thread
    DWORD dwExitCode //exit code
);

(2).结束函数所在的线程 

1
2
3
VOID ExitThread(
    DWORD dwExitCode //exit code for this thread
);

 五、线程的相关操作

(1).获取当前线程的ID:GetCurrentThreadId

(2).获取当前线程的句柄:GetCurrentThread

(3).等候单个句柄有信号:

1
2
3
4
VOID WaitForSingleObject(
    HANDLE handle, //句柄BUFF的地址
    DWORD dwMilliseconds //等候时间INFINITE
);

(3).同时等候多个句柄有信号 

1
2
3
4
5
6
7
8
9
VOID WaitForMultipleObjects(
    DWORD nCount, //句柄数量
    CONST HANDLE *lpHandle, //句柄BUFF的地址
    BOOL bWait, //等候方式
    DWORD dwMilliseconds //等候时间INFINITE
);
bWaitAll(等候方式):
    TRUE:表示所有句柄都有信号,才结束等候
    FALSE:表示句柄中只要有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
#include <Windows.h>
#include <iostream>
 
using namespace std;
 
DWORD CALLBACK ThreadProc(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        cout << szText << endl;
        Sleep(1000);
    }
 
    return 0;
}
 
DWORD CALLBACK ThreadProc1(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        cout << szText << endl;
        Sleep(1000);
    }
 
    return 0;
}
 
int main() {
    const char* pszText = "********";
    DWORD nID = 0;
    //线程立即执行
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)pszText, 0, &nID);
    if (hThread == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    WaitForSingleObject(hThread, INFINITE);
 
    const char* pszText1 = "--------";
    DWORD nID1 = 0;
    //线程挂起
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, (LPVOID)pszText1, 0, &nID1);
    if (hThread1 == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    system("pause");
 
    return 1;
}

六、线程同步

1.原子锁

(1).相关问题:多个线程对同一个数据进行原子操作,会产生结果丢失,比如执行++运算

(2).错误代码分析:当线程A执行g_value++时,如果线程切换时间正好是线程A将值保存到g_value之前线程B继续执行g_value++,那么当线程A再次被切换回来之后,会将原来线程A保存的值保存到g_value上,线程B进行的加法操作被覆盖。

 (3).使用原子锁函数

1
2
3
4
InterlockedIncrement
InterlockedDecrement
InterlockedCompareExchange
InterlockedExchange

原子锁的实现:直接对数据所在的内存操作,并且 在任何一个瞬间只能有一个线程访问 

示例代码:

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
#include <Windows.h>
#include <iostream>
 
using namespace std;
 
long g_value = 0;
 
DWORD CALLBACK ThreadProc(LPVOID pParam) {
    for (int i = 0; i < 100000000; i++) {
        InterlockedIncrement(&g_value);
    }
 
    return 0;
}
 
DWORD CALLBACK ThreadProc1(LPVOID pParam) {
    for (int i = 0; i < 100000000; i++) {
        InterlockedIncrement(&g_value);
    }
 
    return 0;
}
 
int main() {
    DWORD nID = 0;
    HANDLE hThread[2];
    hThread[0] = CreateThread(NULL, 0, ThreadProc, NULL, 0, &nID);
    hThread[1] = CreateThread(NULL, 0, ThreadProc1, NULL, 0, &nID);
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
 
    cout << "wait over" << endl;
 
    cout << g_value << endl;
 
    return 1;
}

 2.互斥锁

(1).相关的问题:多线程下代码或资源的共享使用

(2).创建互斥锁:

1
2
3
4
5
6
HANDLE CreateMutex(
    LPSECURITY_ATTRIBUTES lpMutextAttributes, //安全属性
    BOOL bInitialOwner, //初始化的拥有者 TRUE(主线程拥有互斥)/FALSE(任何线程都不拥有互斥)
    LPCTSTR lpName //命名
)
创建成功后返回互斥句柄

(3).等候互斥:WaittFor...互斥的等候遵循谁先等候谁先获取

(4).释放互斥锁:

1
2
3
BOOL ReleaseMutex(
    HANDLE hMutex //handle to mutex
);

(5).关闭互斥句柄:CloseHandle  

示例代码:

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 <Windows.h>
#include <iostream>
 
using namespace std;
 
HANDLE g_hMutex = 0;//互斥句柄
 
DWORD CALLBACK ThreadProc(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    while (true) {
        Sleep(1000);
        //当任何线程拥有互斥的时候,则阻塞等待,反正则不阻塞继续执行,此时这个线程就拥有了互斥
        //线程拥有互斥,则无信号阻塞等待,当所有线程都不拥有互斥,则是有信号,可以继续执行下去
        WaitForSingleObject(g_hMutex, INFINITE);
        for (int i = 0; i < strlen(szText); i++) {
            printf("%c", szText[i]);
            Sleep(125);
        }
        printf("\n");
        ReleaseMutex(g_hMutex);
    }
 
    return 0;
}
 
DWORD CALLBACK ThreadProc1(LPVOID lpThreadParameter) {
    char* szText = (char*)lpThreadParameter;
    Sleep(1000);
    while (true) {
        WaitForSingleObject(g_hMutex, INFINITE);
        for (int i = 0; i < strlen(szText); i++) {
            printf("%c", szText[i]);
            Sleep(125);
        }
        printf("\n");
        ReleaseMutex(g_hMutex);
    }
 
    return 0;
}
 
int main() {
    g_hMutex = CreateMutex(NULL, FALSE, NULL);
 
    const char* pszText = "********";
    DWORD nID = 0;
    //线程立即执行
    HANDLE hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)pszText, 0, &nID);
    if (hThread == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    const char* pszText1 = "--------";
    DWORD nID1 = 0;
    //线程挂起
    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, (LPVOID)pszText1, 0, &nID1);
    if (hThread1 == NULL) {
        cout << "create thread failed" << GetLastError();
    }
 
    getchar();
 
    CloseHandle(g_hMutex);
 
    return 1;
}

3.事件

(1).相关问题:线程之间的通知的问题

(2).创建事件:

1
2
3
4
5
6
7
8
HANDLE CreateEvent(
    LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性 
    //由有信号变成无信号为复位,而由无信号变成有信号则为触发
    BOOL bManualReset, //事件重置(复位)方式,TRUE手动,FALSE自动
   BOOL bInitialSate, //事件初始状态,TRUE有信号
    LPCTSTR lpName //事件名
);
创建成功后返回事件句柄

  

(3).等候事件:WaitForSingleObject/WaitForMultipleObjects 

(4).触发事件(将事件设置成有信号状态)

1
2
3
BOOL SetEvent(
    HANDLE hEvent //handle to event
);

(5).复位事件(将事件设置成无信号状态)

1
2
3
BOOL ResetEvent(
    HANDLE hEvent //handle to vent  
);

(6).关闭事件:CloseHandle  

示例代码:

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
#include <Windows.h>
#include <stdio.h>
 
HANDLE g_hEvent = NULL; //事件句柄
 
DWORD CALLBACK PrintProc(LPVOID lpThreadParameter) {
    while (true) {
        WaitForSingleObject(g_hEvent, INFINITE);
        printf("**************************\n");
        ResetEvent(g_hEvent);
    }
 
    return 1;
}
 
DWORD CALLBACK CtrlProc(LPVOID lpThreadParameter) {
    while (true) {
        Sleep(1000);
        SetEvent(g_hEvent);
    }
 
    return 1;
}
 
int main() {
    g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    DWORD nID = 0;
    HANDLE hThread[2] = { 0 };
    hThread[0] = CreateThread(NULL, 0, PrintProc, NULL, 0, &nID);
    hThread[1] = CreateThread(NULL, 0, CtrlProc, NULL, 0, &nID);
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
 
    CloseHandle(g_hEvent);
 
    return 1;
}

4.信号量

(1).相关的问题:类似于事件,解决通知的相关问题,但提供一个计数器,可以设置次数

(2).创建信号量:

1
2
3
4
5
6
7
HANDLE CreateSemaphore(
    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //安全属性
    LONG lInitialCount, //初始化信号量数量
    LONG lMaximumCount, //信号量的最大值
    LPCTSTR lpName //命名
);
创建成功后返回信号量句柄

(3).等候信号量:WaitFor...每等候通过一次,信号量的信号减1,直到为0阻塞

(4).给信号量指定计数值:

1
2
3
4
5
BOOL ReleaseSemaphore(
    HANDLE hSemaphore, //信号量句柄
    LONG lReleaseCount, //释放数量
    LPLONG lpPreviouseCount //释放前原来信号量的数量,可以为NULL
);

(5).关闭句柄:CloseHandle

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Windows.h>
#include <stdio.h>
 
HANDLE g_hSema = NULL; //信号量句柄
 
DWORD CALLBACK SemaProc(LPVOID lpThreadParameter) {
    while (true) {
        WaitForSingleObject(g_hSema, INFINITE);
        printf("******************\n");
    }
    return 0;
}
 
int main() {
    g_hSema = CreateSemaphore(NULL, 3, 10, NULL);
    DWORD nID = 0;
    HANDLE hThread = CreateThread(NULL, 0, SemaProc, NULL, 0, &nID);
    getchar();
    ReleaseSemaphore(g_hSema, 5, NULL);
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(g_hSema);
 
    return 0;
}

 

posted @   TechNomad  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示