win32 多线程编程

青旅半醒 2022-10-06 05:48 295阅读 0赞
  1. #include <iostream>
  2. #include <Windows.h>
  3. #include<tlhelp32.h>
  4. using namespace std;
  5. #include <string>
  6. DWORD WINAPI myRun(
  7. _In_ LPVOID lpParameter
  8. ) {
  9. cout << "子线程的第一个信息" << endl;
  10. Sleep(200);
  11. cout << "子线程的第二个信息" << endl;
  12. //可以自行强制调用这个函数退出
  13. //while (true)
  14. //{
  15. //ExitThread(0);
  16. //}
  17. //退出代码
  18. return EXIT_SUCCESS;
  19. }
  20. int main()
  21. {
  22. DWORD threadId;
  23. HANDLE threadHandle = CreateThread(NULL,//是否返回的句柄能让子进程继承
  24. 0,//设置线程栈大小。越小递归深度越深,但是栈帧内存越小,0是默认设置
  25. myRun,//方法指针,线程运行时会调用这个函数
  26. NULL,//可传入任意的指针给线程参数
  27. CREATE_SUSPENDED,//线程启动参数,传入0线程创建时立即运行。CREATE_SUSPENDED会在ResumeThread 才运行
  28. &threadId//传出 线程id
  29. );
  30. cout << "主线程准备让子线程运行" << endl;
  31. //由于创建指定了CREATE_SUSPENDED所以必须在ResumeThread才运行
  32. ResumeThread(threadHandle);
  33. //给子线程打印的机会
  34. Sleep(100);
  35. cout << "主线程准备挂起线程" << endl;
  36. //挂起线程
  37. SuspendThread(threadHandle);
  38. //给子线程打印的机会
  39. Sleep(500);
  40. cout << "主线程恢复子线程运行" << endl;
  41. //恢复线程
  42. ResumeThread(threadHandle);
  43. //强制退出某个线程,注意资源释放问题
  44. //TerminateThread(threadHandle,0);
  45. //等候线程结束
  46. WaitForSingleObject(threadHandle, INFINITE);
  47. DWORD exitCode;
  48. GetExitCodeThread(threadHandle,&exitCode);
  49. cout << "子线程退出code " << exitCode << endl;
  50. CloseHandle(threadHandle);
  51. return EXIT_SUCCESS;
  52. }

在这里插入图片描述

多线程同步问题

下面有一个小实验:两个线程对同一共享变量进行各自自增100000次,最后的结果预测的情况应该是200000

  1. //共享变量
  2. int i = 0;
  3. //多个线程同时运行函数
  4. DWORD WINAPI myRun( _In_ LPVOID lpParameter) {
  5. for (size_t j = 0; j < 100000; j++){
  6. ++::i;
  7. }
  8. //退出代码
  9. return EXIT_SUCCESS;
  10. }
  11. int main()
  12. {
  13. DWORD threadId;
  14. HANDLE threadHandle = CreateThread(NULL,//是否返回的句柄能让子进程继承
  15. 0,//设置线程栈大小。越小递归深度越深,但是栈帧内存越小,0是默认设置
  16. myRun,//方法指针,线程运行时会调用这个函数
  17. NULL,//可传入任意的指针给线程参数
  18. CREATE_SUSPENDED,//线程启动参数,传入0线程创建时立即运行。CREATE_SUSPENDED会在ResumeThread 才运行
  19. &threadId//传出 线程id
  20. );
  21. ResumeThread(threadHandle);
  22. DWORD threadId2;
  23. HANDLE threadHandle2 = CreateThread(NULL,//是否返回的句柄能让子进程继承
  24. 0,//设置线程栈大小。越小递归深度越深,但是栈帧内存越小,0是默认设置
  25. myRun,//方法指针,线程运行时会调用这个函数
  26. NULL,//可传入任意的指针给线程参数
  27. CREATE_SUSPENDED,//线程启动参数,传入0线程创建时立即运行。CREATE_SUSPENDED会在ResumeThread 才运行
  28. &threadId2//传出 线程id
  29. );
  30. ResumeThread(threadHandle2);
  31. //等候线程结束
  32. WaitForSingleObject(threadHandle, INFINITE);
  33. WaitForSingleObject(threadHandle2, INFINITE);
  34. cout<<"cur "<<i<<endl;
  35. CloseHandle(threadHandle);
  36. CloseHandle(threadHandle2);
  37. return EXIT_SUCCESS;
  38. }

在这里插入图片描述

对于这个现象网上有很多解释大家可以自己自行查阅 原子性相关文献。
对于自增的共享变量我们可以采用win32提供原子性操作API:
列表如下:
在这里插入图片描述
我们将代码修改如下

  1. int i = 0;
  2. DWORD WINAPI myRun(
  3. _In_ LPVOID lpParameter
  4. ) {
  5. for (size_t j = 0; j < 100000; j++)
  6. {
  7. //保证i操作是原子性的自增
  8. InterlockedIncrement((unsigned int *)&i);
  9. }
  10. //退出代码
  11. return EXIT_SUCCESS;
  12. }

在这里插入图片描述

当然对于复杂的情况我们也可以使用临界区函数:

  1. lude <string>
  2. //临界区
  3. CRITICAL_SECTION cs;
  4. int i = 0;
  5. DWORD WINAPI myRun(
  6. _In_ LPVOID lpParameter
  7. ) {
  8. for (size_t j = 0; j < 100000; j++)
  9. {
  10. //仅有一个线程能进入临界区
  11. EnterCriticalSection(&cs);
  12. ++::i;
  13. //InterlockedIncrement((unsigned int *)&i);
  14. LeaveCriticalSection(&cs);
  15. }
  16. //退出代码
  17. return EXIT_SUCCESS;
  18. }
  19. int main()
  20. {
  21. //初始化临界区
  22. InitializeCriticalSection(&cs);
  23. //...略
  24. //回收临界区资源
  25. DeleteCriticalSection(&cs);
  26. return EXIT_SUCCESS;
  27. }

发表评论

表情:
评论列表 (有 0 条评论,295人围观)

还没有评论,来说两句吧...

相关阅读

    相关 win32 线

    线程是不能但对存在的,其必须存在在进程的地址空间中。一个线程在这段地址空间仅有两样东西 一个线程的内核对象,操作系统使用这个数据结构来管理线程。 一个线程栈,其中

    相关 Win32_1-线创建

    线程句柄与线程ID: 线程是由Windows内核负责创建与管理的,句柄相当于一个令牌,有了这个令牌就可以使用线程对象. 线程ID是身份证,唯一的,系统进行线程调度的时候要使