CreateThread用法详解[通俗易懂]

CreateThread用法详解[通俗易懂]CreateThread用法详解今天我给大家讲一讲C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面我就此简单的讲一下:创建线程的函数  HANDLE CreateThread(     LPSECURITY_ATTRIBUTES lpThreadAttributes, //

大家好,又见面了,我是你们的朋友全栈君。

                    CreateThread用法详解

今天我给大家讲一讲C++中的多线程编程技术,C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面我就此简单的讲一下:

创建线程的函数

  HANDLE CreateThread( 

    LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

    SIZE_T dwStackSize,                       // initial stack size

    LPTHREAD_START_ROUTINE lpStartAddress,    // thread function

    LPVOID lpParameter,                       // thread argument

    DWORD dwCreationFlags,                    // creation option

    LPDWORD lpThreadId                        // thread identifier

  );

  

在这里我们只用到了第三个和第四个参数,第三个参数传递了一个函数的地址,也是我们要指定的新的线程。第四个参数是传给新线程的参数指针

  eg1

  #include <iostream>

  #include <windows.h>

  using namespace std;

  DWORD WINAPI Fun(LPVOID lpParamter)

  {

        while(1) { cout<<“Fun display!”<<endl; }

  }

  int main()

  {

      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);

      CloseHandle(hThread);

      while(1) { cout<<“main display!”<<endl;  }

      return 0;

  }

我们可以看到主线程(main函数)和我们自己的线程(Fun函数)是随机地交替执行的,但是两个线程输出太快,使我们很难看清楚,我们可以使用函数

  VOID Sleep(

    DWORD dwMilliseconds   // sleep time

  );

来暂停线程的执行,dwMilliseconds表示千分之一秒,所以

  Sleep(1000);

表示暂停1

  eg2:

  

  #include <iostream>

  #include <windows.h>

  using namespace std;

  DWORD WINAPI Fun(LPVOID lpParamter)

  {

        

        while(1) { cout<<“Fun display!”<<endl; Sleep(1000);}

  }

  int main()

  {

      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);

      CloseHandle(hThread);

      while(1) { cout<<“main display!”<<endl;  Sleep(2000);}

      return 0;

  }

  执行上述代码,这次我们可以清楚地看到在屏幕上交错地输出Fun display!main display!,我们发现这两个函数确实是并发运行的,细心的读者可能会发现我们的程序是每当Fun函数和main函数输出内容后就会输出换行,但是我们看到的确是有的时候程序输出换行了,有的时候确没有输出换行,甚至有的时候是输出两个换行。这是怎么回事?下面我们把程序改一下看看:

  eg3

  

  #include <iostream>

  #include <windows.h>

  using namespace std;

  DWORD WINAPI Fun(LPVOID lpParamter)

  {

        

        while(1) { cout<<“Fun display!\n”; Sleep(1000);}

  }

  int main()

  {

      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);

      CloseHandle(hThread);

      while(1) { cout<<“main display!\n”;  Sleep(2000);}

      return 0;

  }

  我们再次运行这个程序,我们发现这时候正如我们预期的,正确地输出了我们想要输出的内容并且格式也是正确的。下面我就来讲一下此前我们的程序为什么没有正确的运行。多线程的程序时并发地运行的,多个线程之间如果公用了一些资源的话,我们并不能保证这些资源都能正确地被利用,因为这个时候资源并不是独占的,举个例子吧:

  eg4

  加入有一个资源 int a = 3

  有一个线程函数 selfAdd() 该函数是使a = a+a

  又有一个线程函数 selfSub() 该函数是使a = a-a

  

  我们假设上面两个线程正在并发欲行,如果selfAdd在执行的时候,我们的目的是想让a编程6,但此时selfSub得到了运行的机会,所以a变成了0,等到selfAdd的到执行的机会后,a = a+a ,但是此时a确是0,并没有如我们所预期的那样的到6,我们回到前面eg2,在这里,我们可以把屏幕看成是一个资源,这个资源被两个线程所共用,加入当Fun函数输出了Fun display!后,将要输出endl(也就是清空缓冲区并换行,在这里我们可以不用理解什么事缓冲区),但此时main函数确得到了运行的机会,此时Fun函数还没有来得及输出换行就把CPU让给了main函数,而这时main函数就直接在Fun display!后输出main display!,至于为什么有的时候程序会连续输出两个换行,读者可以采用同样的分析方法来分析,在这里我就不多讲了,留给读者自己思考了。

那么为什么我们把eg2改成eg3就可以正确的运行呢?原因在于,多个线程虽然是并发运行的,但是有一些操作是必须一气呵成的,不允许打断的,所以我们看到eg2eg3的运行结果是不一样的。

  那么,是不是eg2的代码我们就不可以让它正确的运行呢?答案当然是否,下面我就来讲一下怎样才能让eg2的代码可以正确运行。这涉及到多线程的同步问题。对于一个资源被多个线程共用会导致程序的混乱,我们的解决方法是只允许一个线程拥有对共享资源的独占,这样就能够解决上面的问题了。

  HANDLE CreateMutex(

    LPSECURITY_ATTRIBUTES lpMutexAttributes,  // SD

    BOOL bInitialOwner,                       // initial owner

    LPCTSTR lpName                            // object name

  );

该函数用于创造一个独占资源,第一个参数我们没有使用,可以设为NULL,第二个参数指定该资源初始是否归属创建它的进程,第三个参数指定资源的名称。

  HANDLE hMutex = CreateMutex(NULL,TRUE,”screen”); 

这条语句创造了一个名为screen并且归属于创建它的进程的资源

  

  BOOL ReleaseMutex(

    HANDLE hMutex   // handle to mutex

  );

该函数用于释放一个独占资源,进程一旦释放该资源,该资源就不再属于它了,如果还要用到,需要重新申请得到该资源。申请资源的函数如下

  DWORD WaitForSingleObject(

    HANDLE hHandle,        // handle to object

    DWORD dwMilliseconds   // time-out interval

  );

第一个参数指定所申请的资源的句柄,第二个参数一般指定为INFINITE,表示如果没有申请到资源就一直等待该资源,如果指定为0,表示一旦得不到资源就返回,也可以具体地指定等待多久才返回,单位是千分之一秒。好了,该到我们来解决eg2的问题的时候了,我们可以把eg2做一些修改,如下

  eg5

  

  #include <iostream>

  #include <windows.h>

  using namespace std;

  HANDLE hMutex;

  DWORD WINAPI Fun(LPVOID lpParamter)

  {

        

        while(1) { 

                 WaitForSingleObject(hMutex, INFINITE);

                 cout<<“Fun display!”<<endl; 

                 Sleep(1000);

                 ReleaseMutex(hMutex);

        }

  }

  int main()

  {

      HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);

      hMutex = CreateMutex(NULL, FALSE, “screen”);

      CloseHandle(hThread);

      while(1) {

               WaitForSingleObject(hMutex, INFINITE);

               cout<<“main display!”<<endl;  

               Sleep(2000);

               ReleaseMutex(hMutex);

      }

      return 0;

  }

运行代码正如我们所预期的输出了我们想要输出的内容。好了,终于讲完

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/157330.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 一比一还原axios源码(一)—— 发起第一个请求

    上一篇文章,我们简单介绍了XMLHttpRequest及其他可以发起AJAX请求的API,那部分大家有兴趣可以自己去扩展学习。另外,简单介绍了怎么去读以及我会怎么写这个系列的文章,那么下面就开始真正的

  • 十五、组合模式—— 容器与内容的一致性 #和设计模式一起旅行#

    组合具有一致性…故事背景坚持去输出真的很不容易,今天的的天气真的是热啊!我之前一直想些一个系列是和设计模式去旅行,通过构思一些场景,让自己更好的理解和表达设计模式,但是有时候为了思考一个适合的故事会花费很多时间,so,从这里开始,如果后面的设计模式想到了好的场景的话就写故事背景,要不就简单介绍,重点看故事主角。在现实生活中很多地方我们会使用到树形结构,在软件中也随处可见,例…

  • B样条曲线与贝塞尔曲线学习笔记

    B样条曲线与贝塞尔曲线学习笔记贝塞尔曲线基本公式:B(t)=∑i=0n(in)Pi(1−t)n−iti,t∈[0,1]基本公式:B(t)=\sum_{i=0}^{n}\Big({_i^n}\Big)P_i(1-t)^{n-i}t^i,t\in[0,1]基本公式:B(t)=i=0∑n​(in​)Pi​(1−t)n−iti,t∈[0,1]三次贝塞尔曲线:B(t)=P0(1−t)3+3P1t(1−t)2+3P2t2(1−t)…

  • pycharm 2021.4.14激活码_通用破解码[通俗易懂]

    pycharm 2021.4.14激活码_通用破解码,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • C++版OpenCV使用支持向量机svm进行mnist手写数字识别

    C++版OpenCV使用支持向量机svm进行mnist手写数字识别支持向量机svm也是一种机器学习算法,采用空间超平面进行数据分割,在这篇博客中我们将使用svm进行手写数字的识别,使用该算法,识别率可以达到100%。环境准备:vs2015OpenCV4.5.0下面的代码为svm模型训练代码:#include<iostream>#include<opencv.hpp>#include<string>#include<fstream>usingnamespacestd;usingnamespace

  • 基于单片机的毕业设计题目_单片机课题

    基于单片机的毕业设计题目_单片机课题地铁报站系统方案说明经过酷毕啦电子设计室3个月的奋斗和不限努力,设计出了2款有个报站系统的课题:一种为自动报站系统;一种为无线控制报站系统,该系统除了可以设计为地铁报站系统,还可以设计成公交报站系统,有需要了解和学习的同学可以加q:3407232510来进行学习和探讨。本系统所有的全国各地的地铁,无论几号线,都实用这套系统,完全个性定制!产品视频讲解视频链接*(以长沙地铁2号线讲解为例):htt…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号