• windows系统编程1——线程和进程


    学习视频链接

    03进程的创建_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Fd4y1G7Td?p=3&vd_source=0471cde1c644648fafd07b54e303c905

    目录

    一、创建线程

    二、线程间同步

    2.1  线程不同步的结果

    2.2 原子操作上锁

    2.3 临界区

    2.4 内核对象

    三、线程间通信

    四、进程的创建

    五、进程间通信

    5.1 通信方式分类

    5.2  共享内存的写法


    一、创建线程

    1. #include
    2. #include
    3. using namespace std;
    4. // 回调函数
    5. DWORD WINAPI ThreadProc(PVOID lp)
    6. {
    7. int i = 0;
    8. while (i < 10) {
    9. Sleep(200);
    10. i++;
    11. printf("SubThread: %d\n", i);
    12. }
    13. return 0;
    14. }
    15. int main()
    16. {
    17. //CreateThread(NULL, 0, ThreadProc, 0, 0, 0); // 创建,不开启线程
    18. HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, CREATE_SUSPENDED, 0); // 创建,开启线程
    19. int i = 10;
    20. while (i < 20) {
    21. Sleep(200);
    22. i++;
    23. printf("ParentThread: %d\n", i);
    24. }
    25. ResumeThread(h); // 开启线程
    26. Sleep(3000);
    27. return 0;
    28. }

    h 代表句柄

    如果关闭两次线程就需要开启两次线程

    二、线程间同步

    2.1  线程不同步的结果

    1. #include
    2. #include
    3. using namespace std;
    4. int g = 0;
    5. // 回调函数
    6. DWORD WINAPI ThreadProc(PVOID lp)
    7. {
    8. for (int i = 0; i < 1000000; i++) {
    9. g++;
    10. }
    11. return 0;
    12. }
    13. int main()
    14. {
    15. HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
    16. for (int i = 0; i < 1000000; i++) {
    17. g++;
    18. }
    19. WaitForSingleObject(h, INFINITE); // 无限等待
    20. printf("%d\n", g);
    21. CloseHandle(h); // 关闭线程
    22. return 0;
    23. }

    子线程和主线程可能同时写主线程,导致不能够达到预期的 2000000

    2.2 原子操作上锁

    1. #include
    2. #include
    3. using namespace std;
    4. unsigned int g = 0;
    5. // 回调函数
    6. DWORD WINAPI ThreadProc(PVOID lp)
    7. {
    8. for (int i = 0; i < 1000000; i++) {
    9. InterlockedIncrement(&g);
    10. }
    11. return 0;
    12. }
    13. int main()
    14. {
    15. HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
    16. for (int i = 0; i < 1000000; i++) {
    17. InterlockedIncrement(&g);
    18. }
    19. WaitForSingleObject(h, INFINITE); // 无限等待
    20. printf("%d\n", g);
    21. CloseHandle(h); // 关闭线程
    22. return 0;
    23. }

    2.3 临界区

    1. #include
    2. #include
    3. using namespace std;
    4. int g = 0;
    5. CRITICAL_SECTION g_sec; // 创建临界区对象
    6. // 回调函数
    7. DWORD WINAPI ThreadProc(PVOID lp)
    8. {
    9. for (int i = 0; i < 100000; i++) {
    10. EnterCriticalSection(&g_sec); // 进入临界区
    11. g++;
    12. LeaveCriticalSection(&g_sec);
    13. }
    14. return 0;
    15. }
    16. int main()
    17. {
    18. // 初始化临界区对象
    19. InitializeCriticalSection(&g_sec);
    20. HANDLE h = CreateThread(0, 0, ThreadProc, 0, 0, 0);
    21. for (int i = 0; i < 100000; i++) {
    22. EnterCriticalSection(&g_sec);
    23. g++;
    24. LeaveCriticalSection(&g_sec);
    25. }
    26. WaitForSingleObject(h, INFINITE); // 无限等待线程执行完
    27. printf("%d\n", g);
    28. // 句柄释放
    29. CloseHandle(h);
    30. return 0;
    31. }

    2.4 内核对象

    1、内核对象

    每一个内核对象在任何时候都处于两种状态之一:信号态和无信号态

    线程在等待其中的一个或多个内核对象时,如果在等待的一个或多个内核对象处于无信号态,线程自身将被系统挂起,直到等待的内核对象变为有信号状态时,线程才恢复运行。常用的等待函数有 2 个

    2、等待线程函数

    在多线程下面,有时候我们会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用 Windows API 函数 WaitForSingleObject,或者 WaitForMultipleObjects。这两个函数都会等待 Object 被标为有信号时才返回的。这两个函数的优点是它们在等待的过程中会进入一个非常高效沉睡状态,只占用极少的 CPU 时间片

    (1) 信号

    1. #include
    2. #include
    3. using namespace std;
    4. int g = 0;
    5. HANDLE hmutex;
    6. // 回调函数
    7. DWORD WINAPI ThreadProc(PVOID lp)
    8. {
    9. for (int i = 0; i < 100000; i++) {
    10. WaitForSingleObject(hmutex, INFINITE); // hmutex 有信号->无信号
    11. g++;
    12. ReleaseMutex(hmutex); // hmutex 无信号->有信号
    13. }
    14. return 0;
    15. }
    16. int main()
    17. {
    18. // 创建内核对象
    19. hmutex = CreateMutex(NULL, FALSE, NULL); // hmutex 创建->有信号
    20. HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
    21. for (int i = 0; i < 100000; i++) {
    22. WaitForSingleObject(hmutex, INFINITE); // hmutex 有信号->无信号
    23. g++;
    24. ReleaseMutex(hmutex); // hmutex 无信号->有信号
    25. }
    26. WaitForSingleObject(h, INFINITE); // 无限等待线程执行完
    27. printf("%d\n", g);
    28. // 释放内核释放
    29. CloseHandle(h);
    30. CloseHandle(hmutex);
    31. return 0;
    32. }

    (2) 事件

    1. #include
    2. #include
    3. using namespace std;
    4. int g = 0;
    5. HANDLE hEvent;
    6. // 回调函数
    7. DWORD WINAPI ThreadProc(PVOID lp)
    8. {
    9. for (int i = 0; i < 100000; i++) {
    10. WaitForSingleObject(hEvent, INFINITE); // hmutex 有事件->无事件
    11. g++;
    12. SetEvent(hEvent); // hmutex 无事件->有事件
    13. }
    14. return 0;
    15. }
    16. int main()
    17. {
    18. // 创建事件对象
    19. hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
    20. HANDLE h = CreateThread(NULL, 0, ThreadProc, 0, 0, 0);
    21. for (int i = 0; i < 100000; i++) {
    22. WaitForSingleObject(hEvent, INFINITE); // hmutex 有事件->无事件
    23. g++;
    24. SetEvent(hEvent); // hmutex 无事件->有事件
    25. }
    26. WaitForSingleObject(h, INFINITE); // 无限等待线程执行完
    27. printf("%d\n", g);
    28. // 释放内核释放
    29. CloseHandle(h);
    30. CloseHandle(hEvent);
    31. return 0;
    32. }

    三、线程间通信

    1、使用全局变量进行通信

    2、参数传递方式

    1. #include
    2. #include
    3. using namespace std;
    4. struct node {
    5. int age;
    6. int id;
    7. };
    8. int g = 0;
    9. HANDLE hEvent;
    10. // 回调函数
    11. DWORD WINAPI ThreadProc(PVOID lp)
    12. {
    13. node n = *(node*)lp;
    14. cout << n.age << " " << n.id << endl;;
    15. for (int i = 0; i < 100000; i++) {
    16. WaitForSingleObject(hEvent, INFINITE); // hmutex 有事件->无事件
    17. g++;
    18. SetEvent(hEvent); // hmutex 无事件->有事件
    19. }
    20. return 0;
    21. }
    22. int main()
    23. {
    24. node n;
    25. n.id = 1;
    26. n.age = 10;
    27. // 创建事件对象
    28. hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
    29. HANDLE h = CreateThread(NULL, 0, ThreadProc, &n, 0, 0);
    30. for (int i = 0; i < 100000; i++) {
    31. WaitForSingleObject(hEvent, INFINITE); // hmutex 有事件->无事件
    32. g++;
    33. SetEvent(hEvent); // hmutex 无事件->有事件
    34. }
    35. WaitForSingleObject(h, INFINITE); // 无限等待线程执行完
    36. printf("%d\n", g);
    37. // 释放内核释放
    38. CloseHandle(h);
    39. CloseHandle(hEvent);
    40. return 0;
    41. }

    3、消息传递方式

    MFC 里面的

    四、进程的创建

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. TCHAR commandLine[] = TEXT("C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe www.baidu.com");
    7. _STARTUPINFOW startInfo = { sizeof(_STARTUPINFOW)};
    8. _PROCESS_INFORMATION processInfo;
    9. /*
    10. BOOL CreateProcess(
    11.   LPCTSTR lpApplicationName, 应用程序名称
    12.   LPTSTR lpCommandLine, 命令行字符串
    13.   LPSECURITY_ATTRIBUTES lpProcessAttributes, 进程的安全属性
    14.   LPSECURITY_ATTRIBUTES lpThreadAttributes, 线程的安全属性
    15.   BOOL bInheritHandles, 是否继承父进程的属性
    16.   DWORD dwCreationFlags, 创建标志
    17.   LPVOID lpEnvironment, 指向新的环境块(环境变量)的指针
    18.   LPCTSTR lpCurrentDirectory, 指向当前目录名的指针
    19.   LPSTARTUPINFO lpStartupInfo, 传递给新进程的信息
    20.   LPPROCESS_INFORMATION lpProcessInformation 新进程返回的信息
    21. );
    22. */
    23. bool ret = CreateProcess(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &startInfo, &processInfo);
    24. if (ret == false) {
    25. cout << "创建进程失败" << endl;
    26. return 0;
    27. }
    28. else {
    29. WaitForSingleObject(processInfo.hProcess, INFINITE);
    30. cout << "新创建的进程ID: " << processInfo.dwProcessId << endl;
    31. cout << "新创建的线程ID: " << processInfo.dwThreadId << endl;
    32. CloseHandle(processInfo.hProcess);
    33. CloseHandle(processInfo.hThread);
    34. }
    35. return 0;
    36. }

    上述代码就完成了打开浏览器进程的任务了

     

    五、进程间通信

    5.1 通信方式分类

    >套接字(socket):

    套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

    5.2  共享内存的写法

    输出字符的程序

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. /*
    7. HANDLE CreateFileMapping(
    8. HANDLE hFile, // 物理文件句柄
    9. LPSECURITY_ATTRIBUTES lpAttributes, // 安全设置
    10. DWORD flProtect, // 保护设置
    11. DWORD dwMaximumSizeHigh, // 高位文件大小
    12. DWORD dwMaximumSizeLow, // 低位文件大小
    13. LPCTSTR lpName // 共享内存名称
    14. );
    15. */
    16. // 创建共享文件句柄
    17. HANDLE hMapFile = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, 1024, TEXT("fileMap"));
    18. char *buf = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
    19. gets_s(buf, 100);
    20. while (1) {
    21. Sleep(1000);
    22. }
    23. UnmapViewOfFile(buf);
    24. CloseHandle(hMapFile);
    25. return 0;
    26. }

    接收字符的程序

    1. #include
    2. #include
    3. using namespace std;
    4. int main()
    5. {
    6. /*
    7. HANDLE CreateFileMapping(
    8. HANDLE hFile, // 物理文件句柄
    9. LPSECURITY_ATTRIBUTES lpAttributes, // 安全设置
    10. DWORD flProtect, // 保护设置
    11. DWORD dwMaximumSizeHigh, // 高位文件大小
    12. DWORD dwMaximumSizeLow, // 低位文件大小
    13. LPCTSTR lpName // 共享内存名称
    14. );
    15. */
    16. // 创建共享文件句柄
    17. HANDLE hMapFile = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0, 1024, TEXT("fileMap"));
    18. char *buf = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
    19. cout << buf << endl;
    20. getchar();
    21. UnmapViewOfFile(buf);
    22. CloseHandle(hMapFile);
    23. return 0;
    24. }

  • 相关阅读:
    Leetcode1106:解析布尔表达式
    JavaScript变量和作用域简介
    优化理论12---- 既约梯度法
    亚马逊云科技Glue
    SpringBoot事务失效场景、事务正确使用姿势
    线性表的线性表示;初始化,输出,插入,删除,查找;
    【2024秋招】2023-10-9 同花顺后端笔试题
    window-linux文件备份
    Js 对于一个时间戳,只改变其年份,求改变之后的时间戳。
    C#调用C++ dll 返回数组
  • 原文地址:https://blog.csdn.net/HuanBianCheng27/article/details/126808312