• C
  • windows C语言多线程的教程 通俗易懂 快速上手

  • @ 2025-2-21 19:59:48

小朋友,我们来一起学习Windows下C语言的多线程哦,就像玩游戏一样有趣!

1. 准备工作

首先呢,我们要在电脑上安装一个能写C语言程序的软件,比如Visual Studio。就好像画画得先有画笔和纸一样,有了这个软件,我们才能写代码。

2. 多线程是什么

想象一下,你有一个大任务,比如整理好多玩具。如果只有你一个人做,可能要花很久。但要是有几个小伙伴一起帮忙,每个人负责一部分,就能很快完成啦。在电脑程序里也是这样,多线程就是让几个“小伙伴线程”一起做事,让程序跑得更快,能同时做更多的任务。

3. 开始写代码啦

打开我们安装好的软件,新建一个C语言项目。然后在代码文件里,我们要先写一些“魔法咒语”,也就是头文件:

#include <windows.h>
#include <stdio.h>

#include <windows.h> 就像是打开了Windows世界的大门,让我们能用Windows系统提供的各种工具;#include <stdio.h> 是为了能在屏幕上显示文字和接收我们输入的东西。

4. 创造线程小伙伴

我们要写一个“小伙伴线程”要做的事情,这就像给小伙伴安排任务。比如,我们让它在屏幕上打印一句话:

// 线程要做的事情,就像小伙伴的任务
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
    printf("我是新线程,我在工作啦!\n");
    return 0;
}

这里的 DWORD WINAPI 是一种规定的写法,告诉电脑这是线程要做的函数。MyThreadFunction 是我们给这个任务起的名字,LPVOID lpParam 是用来给这个任务传递东西的(现在我们先不管它)。

接下来,在 main 函数里,我们要把这个小伙伴线程创造出来:

int main() {
    HANDLE hThread; // 这是用来记住我们创造的线程的
    DWORD threadId; // 线程的身份证号

    // 创造线程小伙伴
    hThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId);
    if (hThread == NULL) {
        printf("创造线程失败啦,呜呜\n");
        return 1;
    }

    // 等线程小伙伴把事情做完
    WaitForSingleObject(hThread, INFINITE);

    // 用完线程小伙伴后,把它的“房间”打扫干净
    CloseHandle(hThread);

    printf("我是主线程,我也做完啦!\n");
    return 0;
}

CreateThread 这里,我们就像在召唤一个线程小伙伴出来。NULL 就像一些默认的设置,0 是给线程的一些资源大小,MyThreadFunction 就是我们之前给它安排的任务,后面的 NULL 是给任务传递的东西(我们还没用到),&threadId 是把线程的身份证号存起来。

WaitForSingleObject 是让主线程(就像小组长)等这个线程小伙伴把任务做完。最后 CloseHandle 就像是把线程小伙伴用过的东西收拾好,释放资源。

5. 给线程小伙伴传递东西

有时候,我们要给线程小伙伴一些东西让它处理。比如我们给它一个数字,让它打印出来:

#include <windows.h>
#include <stdio.h>

// 线程要做的事情,现在能接收东西啦
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
    int num = *(int*)lpParam;
    printf("我收到的数字是:%d\n", num);
    return 0;
}

int main() {
    HANDLE hThread;
    DWORD threadId;
    int number = 5; // 我们准备给线程的数字

    // 创造线程小伙伴,把数字传过去
    hThread = CreateThread(NULL, 0, MyThreadFunction, &number, 0, &threadId);
    if (hThread == NULL) {
        printf("创造线程失败啦,呜呜\n");
        return 1;
    }

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);

    printf("我是主线程,我也做完啦!\n");
    return 0;
}

这里我们把 number 的地址(&number)传给线程,线程里通过 *(int*)lpParam 把这个数字拿出来用。

6. 让线程小伙伴们排队

当有好几个线程小伙伴都要访问同一个东西(比如一个玩具大家都想玩),就可能会乱套。这时候我们要让它们排队,这就用到互斥锁(Mutex)。

#include <windows.h>
#include <stdio.h>

HANDLE hMutex; // 这是我们的排队工具,互斥锁
int sharedVariable = 0; // 这是大家都想访问的东西,就像那个玩具

// 线程要做的事情
DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
    for (int i = 0; i < 3; ++i) {
        WaitForSingleObject(hMutex, INFINITE); // 排队,等轮到自己
        sharedVariable++;
        printf("线程 %d 让数字变成了:%d\n", GetCurrentThreadId(), sharedVariable);
        ReleaseMutex(hMutex); // 用完了,让给别人
    }
    return 0;
}

int main() {
    HANDLE hThread1, hThread2;
    DWORD threadId1, threadId2;

    // 创建排队工具,互斥锁
    hMutex = CreateMutex(NULL, FALSE, NULL);
    if (hMutex == NULL) {
        printf("创建排队工具失败啦,呜呜\n");
        return 1;
    }

    // 创造两个线程小伙伴
    hThread1 = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId1);
    hThread2 = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId2);
    if (hThread1 == NULL || hThread2 == NULL) {
        printf("创造线程失败啦,呜呜\n");
        CloseHandle(hMutex);
        return 1;
    }

    // 等两个线程小伙伴做完
    WaitForSingleObject(hThread1, INFINITE);
    WaitForSingleObject(hThread2, INFINITE);

    // 把排队工具和线程小伙伴都收拾好
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    CloseHandle(hMutex);

    printf("我是主线程,我也做完啦!\n");
    return 0;
}

CreateMutex 是创建排队工具,WaitForSingleObject 是去排队,ReleaseMutex 是用完后离开队伍,让别人能进来。

小朋友,你可以试着按照这些步骤,在电脑上敲敲代码,看看线程小伙伴们是怎么工作的哦!

4 条评论

  • @ 2025-2-21 20:53:28

    小朋友,下面我们来一起学习Windows系统里用C语言写多线程程序哦,保证你能很快学会!

    1. 准备写代码的地方

    我们得先在电脑上安装一个叫Visual Studio的软件,它就像一个超级厉害的魔法盒子,能帮我们写C语言程序。安装好之后,打开它,新建一个C语言项目,这就好比准备好了画画的纸啦。

    2. 多线程是什么呢

    想象一下,你要写一篇很长的作文,又要给作文配好看的画。要是你一个人做,一会儿写作文,一会儿画画,可能会有点乱,而且花的时间也长。但要是有两个你,一个专门写作文,一个专门画画,就能同时做这两件事,很快就完成啦。在电脑的程序里呀,多线程就像是有好几个“你”一起工作,每个“你”(线程)都能做不同的任务,这样程序就能做得又快又好啦。

    3. 开始写代码

    在新建的项目代码文件里,我们要先写一些神奇的“咒语”,也就是头文件:

    #include <windows.h>
    #include <stdio.h>
    

    #include <windows.h> 就像是打开了Windows这个大城堡的大门,有了它,我们才能用城堡里各种各样的工具,比如创建线程的工具。#include <stdio.h> 是为了能在屏幕上显示我们写的字,还有接收我们从键盘输入的东西。

    4. 创造线程小帮手

    我们要写一个让线程小帮手做的事情,就像给小帮手布置任务。比如,让它在屏幕上跟我们打个招呼:

    // 这是线程小帮手要做的事情哦
    DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
        printf("我是新线程,我开始工作啦!\n");
        return 0;
    }
    

    这里的 DWORD WINAPI 是一种规定的写法,就像游戏里的规则一样,告诉电脑这是线程要做的函数。MyThreadFunction 是我们给这个任务起的名字,很好记吧。LPVOID lpParam 是用来给这个任务传递东西的,不过现在我们先不管它哦。

    接下来,在 main 函数里,我们要把这个线程小帮手召唤出来:

    int main() {
        HANDLE hThread; // 这是用来记住我们创造的线程的,就像给它一个专属标记
        DWORD threadId; // 这是线程的身份证号
    
        // 开始召唤线程小帮手
        hThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId);
        if (hThread == NULL) {
            printf("召唤线程失败啦,呜呜\n");
            return 1;
        }
    
        // 等线程小帮手把事情做完
        WaitForSingleObject(hThread, INFINITE);
    
        // 用完线程小帮手后,把它的“工具”收拾好
        CloseHandle(hThread);
    
        printf("我是主线程,我也做完啦!\n");
        return 0;
    }
    

    CreateThread 这里,我们就像在念召唤咒语。NULL 就像是一些默认的设置,不用我们操心。0 是给线程的一些资源大小,现在我们也不用太懂。MyThreadFunction 就是我们之前给线程小帮手布置的任务。后面的 NULL 是给任务传递的东西,我们还没用到呢。&threadId 是把线程的身份证号存起来,以后就能找到它啦。

    WaitForSingleObject 是让主线程(就像小组长)等这个线程小帮手把任务做完。最后 CloseHandle 就像是把线程小帮手用过的工具收拾好,不能乱扔哦,这样就能释放资源啦。

    5. 给线程小帮手送东西

    有时候,我们要给线程小帮手一些东西让它处理。比如给它一个数字,让它告诉我们这个数字是多少:

    #include <windows.h>
    #include <stdio.h>
    
    // 线程小帮手要做的事情,现在能接收东西啦
    DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
        int num = *(int*)lpParam;
        printf("我收到的数字是:%d\n", num);
        return 0;
    }
    
    int main() {
        HANDLE hThread;
        DWORD threadId;
        int number = 5; // 我们准备给线程的数字
    
        // 召唤线程小帮手,把数字传过去
        hThread = CreateThread(NULL, 0, MyThreadFunction, &number, 0, &threadId);
        if (hThread == NULL) {
            printf("召唤线程失败啦,呜呜\n");
            return 1;
        }
    
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
    
        printf("我是主线程,我也做完啦!\n");
        return 0;
    }
    

    这里我们把 number 的地址(&number)传给线程小帮手,它就能通过 *(int*)lpParam 把这个数字拿出来用啦。

    6. 让线程小帮手们排队

    要是有好多线程小帮手都想玩同一个玩具(就像访问同一个东西),可能就会乱起来。这时候我们得让它们排队,这就要用到互斥锁(Mutex)啦。

    #include <windows.h>
    #include <stdio.h>
    
    HANDLE hMutex; // 这是我们的排队工具,互斥锁
    int sharedVariable = 0; // 这是大家都想玩的玩具,也就是大家都想访问的东西
    
    // 线程小帮手要做的事情
    DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
        for (int i = 0; i < 3; ++i) {
            WaitForSingleObject(hMutex, INFINITE); // 排队,等轮到自己
            sharedVariable++;
            printf("线程 %d 让数字变成了:%d\n", GetCurrentThreadId(), sharedVariable);
            ReleaseMutex(hMutex); // 用完了,让给别人
        }
        return 0;
    }
    
    int main() {
        HANDLE hThread1, hThread2;
        DWORD threadId1, threadId2;
    
        // 创建排队工具,互斥锁
        hMutex = CreateMutex(NULL, FALSE, NULL);
        if (hMutex == NULL) {
            printf("创建排队工具失败啦,呜呜\n");
            return 1;
        }
    
        // 召唤两个线程小帮手
        hThread1 = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId1);
        hThread2 = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, &threadId2);
        if (hThread1 == NULL || hThread2 == NULL) {
            printf("召唤线程失败啦,呜呜\n");
            CloseHandle(hMutex);
            return 1;
        }
    
        // 等两个线程小帮手做完
        WaitForSingleObject(hThread1, INFINITE);
        WaitForSingleObject(hThread2, INFINITE);
    
        // 把排队工具和线程小帮手都收拾好
        CloseHandle(hThread1);
        CloseHandle(hThread2);
        CloseHandle(hMutex);
    
        printf("我是主线程,我也做完啦!\n");
        return 0;
    }
    

    CreateMutex 是创建排队工具,就像做了一个排队的栏杆。WaitForSingleObject 是让线程小帮手去排队,等轮到自己才能玩玩具。ReleaseMutex 是用完玩具后离开队伍,把玩具让给别人。

    小朋友,现在你可以按照这些步骤,在电脑上试着敲敲代码,看看线程小帮手们是怎么一起工作的哟!

    • @ 2025-2-21 20:14:53
      #include <windows.h>
      #include <stdio.h>
      
      // 全局变量,用于模拟一直增加的值
      int value = 0;
      // 用于线程同步的互斥锁
      HANDLE hMutex; 
      
      // 负责让值一直增加的线程函数
      DWORD WINAPI IncreaseThread(LPVOID lpParam) {
          while (true) {
              WaitForSingleObject(hMutex, INFINITE);
              value++;
              ReleaseMutex(hMutex);
              Sleep(1000); // 暂停1秒,让增加的效果明显些
          }
          return 0;
      }
      
      // 负责接收输入的线程函数
      DWORD WINAPI InputThread(LPVOID lpParam) {
          int input;
          while (true) {
              scanf_s("%d", &input); // 在Windows下使用scanf_s更安全
              // 这里可以对输入的input进行处理,比如打印出来
              printf("你输入的值是:%d\n", input); 
              printf("时间是:%d\n", value); 
          }
          return 0;
      }
      
      int main() {
          HANDLE hThread1, hThread2;
          DWORD threadId1, threadId2;
          
          // 创建互斥锁
          hMutex = CreateMutex(NULL, FALSE, NULL);
          if (hMutex == NULL) {
              printf("创建互斥锁失败\n");
              return 1;
          }
          
          // 创建让值增加的线程
          hThread1 = CreateThread(NULL, 0, IncreaseThread, NULL, 0, &threadId1);
          if (hThread1 == NULL) {
              printf("创建增加线程失败\n");
              CloseHandle(hMutex);
              return 1;
          }
          
          // 创建接收输入的线程
          hThread2 = CreateThread(NULL, 0, InputThread, NULL, 0, &threadId2);
          if (hThread2 == NULL) {
              printf("创建输入线程失败\n");
              CloseHandle(hThread1);
              CloseHandle(hMutex);
              return 1;
          }
          
          // 等待线程结束(这里实际上不会结束,只是防止主线程过早退出)
          WaitForSingleObject(hThread1, INFINITE);
          WaitForSingleObject(hThread2, INFINITE);
          
          // 关闭线程句柄和互斥锁
          CloseHandle(hThread1);
          CloseHandle(hThread2);
          CloseHandle(hMutex);
          
          return 0;
      }
      
      
      • @ 2025-2-21 20:01:52

        以下是对上述代码每个部分作用的详细解释:

        头文件引入

        #include <windows.h>
        #include <stdio.h>
        
        • <windows.h>:这是Windows操作系统提供的非常重要的头文件,它包含了大量与Windows系统编程相关的定义、结构体声明和函数原型。在进行Windows下的多线程编程时,诸如线程创建函数CreateThread、同步对象相关函数等都在这个头文件中声明,因此必须引入。
        • <stdio.h>:标准输入输出头文件,提供了像printf(用于输出信息到控制台)和scanf_s(在Windows下更安全的输入函数,用于从控制台读取用户输入)等函数的声明,方便在程序中进行输入输出操作。

        全局变量和互斥锁声明

        // 全局变量,用于模拟一直增加的值
        int value = 0;
        // 用于线程同步的互斥锁
        HANDLE hMutex; 
        
        • value:一个全局整型变量,用于模拟在程序运行过程中一直增加的值。由于多个线程可能会同时访问和修改它,所以需要采取同步措施来保证数据的一致性。
        • hMutex:声明了一个互斥锁句柄,类型为HANDLE。互斥锁是一种用于线程同步的机制,确保在同一时刻只有一个线程能够访问被保护的共享资源(这里就是value变量),防止出现数据竞争和不一致的情况。

        线程函数定义

        让值一直增加的线程函数

        // 负责让值一直增加的线程函数
        DWORD WINAPI IncreaseThread(LPVOID lpParam) {
            while (true) {
                WaitForSingleObject(hMutex, INFINITE);
                value++;
                ReleaseMutex(hMutex);
                Sleep(1000); // 暂停1秒,让增加的效果明显些
            }
            return 0;
        }
        
        • DWORD WINAPI:这是Windows下定义线程函数的特定调用约定和返回类型。DWORD表示无符号长整型,作为函数的返回值类型;WINAPI是一种宏定义,指定了函数的调用约定,它会影响函数参数的传递方式和堆栈的清理方式。
        • IncreaseThread:线程函数的名称,是我们自己定义的,这个线程的主要任务是让value变量不断增加。
        • LPVOID lpParam:函数的参数,类型为LPVOID(即void*,通用指针类型),用于接收从CreateThread函数传递过来的参数。在这个函数中暂时没有使用该参数。
        • while (true):创建一个无限循环,使得该线程持续运行,不断执行后续的操作。
        • WaitForSingleObject(hMutex, INFINITE):调用该函数来等待获取互斥锁hMutexINFINITE表示无限等待,直到成功获取互斥锁。当一个线程调用此函数并获取到互斥锁后,其他线程再调用该函数时就会被阻塞,直到拥有互斥锁的线程释放它。
        • value++:对全局变量value进行自增操作,这是该线程的核心任务。由于在获取互斥锁之后执行,所以能保证同一时刻只有一个线程在修改value,避免数据竞争。
        • ReleaseMutex(hMutex):在完成对value的操作后,调用此函数释放互斥锁,让其他等待获取互斥锁的线程有机会获取并访问共享资源。
        • Sleep(1000):使当前线程暂停执行1000毫秒(即1秒),这样可以让value增加的效果在控制台输出时更加明显,便于观察。

        负责接收输入的线程函数

        // 负责接收输入的线程函数
        DWORD WINAPI InputThread(LPVOID lpParam) {
            int input;
            while (true) {
                scanf_s("%d", &input); // 在Windows下使用scanf_s更安全
                // 这里可以对输入的input进行处理,比如打印出来
                printf("你输入的值是:%d\n", input); 
            }
            return 0;
        }
        
        • InputThread:线程函数的名称,该线程的主要功能是接收用户从控制台输入的数据。
        • 函数内部先声明了一个整型变量input,用于存储用户输入的值。
        • while (true):同样创建一个无限循环,使得该线程能够持续监听用户的输入。
        • scanf_s("%d", &input):使用scanf_s函数从控制台读取用户输入的一个整数,并将其存储到input变量中。在Windows平台上,scanf_s比传统的scanf更安全,它要求指定读取字符串等数据时的缓冲区大小,以防止缓冲区溢出等安全问题。
        • printf("你输入的值是:%d\n", input);:将用户输入的值打印输出到控制台,这里只是简单的示例处理,实际应用中可以根据需求对输入值进行更复杂的处理,比如根据输入值改变程序的运行逻辑等。

        主函数部分

        int main() {
            HANDLE hThread1, hThread2;
            DWORD threadId1, threadId2;
        
            // 创建互斥锁
            hMutex = CreateMutex(NULL, FALSE, NULL);
            if (hMutex == NULL) {
                printf("创建互斥锁失败\n");
                return 1;
            }
        
            // 创建让值增加的线程
            hThread1 = CreateThread(NULL, 0, IncreaseThread, NULL, 0, &threadId1);
            if (hThread1 == NULL) {
                printf("创建增加线程失败\n");
                CloseHandle(hMutex);
                return 1;
            }
        
            // 创建接收输入的线程
            hThread2 = CreateThread(NULL, 0, InputThread, NULL, 0, &threadId2);
            if (hThread2 == NULL) {
                printf("创建输入线程失败\n");
                CloseHandle(hThread1);
                CloseHandle(hMutex);
                return 1;
            }
        
            // 等待线程结束(这里实际上不会结束,只是防止主线程过早退出)
            WaitForSingleObject(hThread1, INFINITE);
            WaitForSingleObject(hThread2, INFINITE);
        
            // 关闭线程句柄和互斥锁
            CloseHandle(hThread1);
            CloseHandle(hThread2);
            CloseHandle(hMutex);
        
            return 0;
        }
        
        • 首先声明了四个变量:
          • hThread1hThread2:类型为HANDLE,用于存储创建的两个线程的句柄。线程句柄是一个标识线程的对象,通过它可以对线程进行各种操作,如等待线程结束、关闭线程等。
          • threadId1threadId2:类型为DWORD,用于存储两个线程的唯一标识符。
        • hMutex = CreateMutex(NULL, FALSE, NULL);:调用CreateMutex函数创建一个互斥锁对象,并将返回的互斥锁句柄赋值给hMutex。三个参数分别表示:
          • 第一个NULL:表示使用默认的安全属性。
          • FALSE:表示互斥锁初始状态为未被任何线程拥有。
          • 第二个NULL:表示互斥锁没有名称(如果为互斥锁指定名称,不同进程中的线程也可以通过名称访问该互斥锁)。
        • 接下来是错误处理,如果hMutexNULL,说明创建互斥锁失败,打印错误信息并返回1,终止程序。
        • hThread1 = CreateThread(NULL, 0, IncreaseThread, NULL, 0, &threadId1);:调用CreateThread函数创建第一个线程,即让值增加的线程:
          • 第一个NULL:表示使用默认的线程安全属性。
          • 0:表示使用默认的线程堆栈大小。
          • IncreaseThread:指定线程启动后要执行的函数。
          • 第二个NULL:表示不向线程函数传递参数。
          • 0:表示线程创建后立即运行。
          • &threadId1:用于接收新创建线程的标识符。
        • 同样有错误处理,如果hThread1NULL,说明创建该线程失败,打印错误信息,关闭之前创建的互斥锁,并返回1终止程序。
        • 以类似的方式,hThread2 = CreateThread(NULL, 0, InputThread, NULL, 0, &threadId2);创建第二个线程,即负责接收输入的线程,并进行相应的错误处理。
        • WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);:这两个函数调用分别让主线程等待hThread1hThread2所代表的线程执行结束。由于这两个线程内部都是无限循环,实际上不会结束,但这样可以防止主线程过早退出,导致子线程还没来得及执行就被终止。
        • CloseHandle(hThread1);CloseHandle(hThread2);CloseHandle(hMutex);:分别关闭两个线程的句柄和互斥锁句柄,释放相关资源,确保程序不会出现资源泄漏的问题。
        • 最后return 0;表示主线程正常结束。
        • @ 2025-2-21 20:01:13

          在Windows的C语言编程中,要实现在主体程序运行时还能进行输入,不被输入操作阻断,可以使用多线程的方式,以下是示例代码:

          #include <windows.h>
          #include <stdio.h>
          
          // 全局变量,用于模拟一直增加的值
          int value = 0;
          // 用于线程同步的互斥锁
          HANDLE hMutex; 
          
          // 负责让值一直增加的线程函数
          DWORD WINAPI IncreaseThread(LPVOID lpParam) {
              while (true) {
                  WaitForSingleObject(hMutex, INFINITE);
                  value++;
                  ReleaseMutex(hMutex);
                  Sleep(1000); // 暂停1秒,让增加的效果明显些
              }
              return 0;
          }
          
          // 负责接收输入的线程函数
          DWORD WINAPI InputThread(LPVOID lpParam) {
              int input;
              while (true) {
                  scanf_s("%d", &input); // 在Windows下使用scanf_s更安全
                  // 这里可以对输入的input进行处理,比如打印出来
                  printf("你输入的值是:%d\n", input); 
              }
              return 0;
          }
          
          int main() {
              HANDLE hThread1, hThread2;
              DWORD threadId1, threadId2;
          
              // 创建互斥锁
              hMutex = CreateMutex(NULL, FALSE, NULL);
              if (hMutex == NULL) {
                  printf("创建互斥锁失败\n");
                  return 1;
              }
          
              // 创建让值增加的线程
              hThread1 = CreateThread(NULL, 0, IncreaseThread, NULL, 0, &threadId1);
              if (hThread1 == NULL) {
                  printf("创建增加线程失败\n");
                  CloseHandle(hMutex);
                  return 1;
              }
          
              // 创建接收输入的线程
              hThread2 = CreateThread(NULL, 0, InputThread, NULL, 0, &threadId2);
              if (hThread2 == NULL) {
                  printf("创建输入线程失败\n");
                  CloseHandle(hThread1);
                  CloseHandle(hMutex);
                  return 1;
              }
          
              // 等待线程结束(这里实际上不会结束,只是防止主线程过早退出)
              WaitForSingleObject(hThread1, INFINITE);
              WaitForSingleObject(hThread2, INFINITE);
          
              // 关闭线程句柄和互斥锁
              CloseHandle(hThread1);
              CloseHandle(hThread2);
              CloseHandle(hMutex);
          
              return 0;
          }
          

          代码说明

          1. 多线程创建:使用CreateThread函数分别创建了两个线程,一个线程函数IncreaseThread用于让全局变量value不断增加,另一个线程函数InputThread用于接收用户的输入。
          2. 线程同步:通过创建互斥锁hMutex,在线程中使用WaitForSingleObjectReleaseMutex来保证对全局变量value的访问是安全的,避免多线程同时访问时出现数据错误。
          3. 输入处理:在InputThread线程函数中,使用scanf_s(Windows下更安全的输入函数)接收用户输入,并对输入进行简单处理(这里只是打印出来)。

          这样,两个线程可以同时运行,实现了主体程序(这里是让值增加的部分)运行的同时还能接收用户输入 。

          • 1