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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?