##本半仙呕心沥血所作,能阅读此卷实乃汝之所幸。
什么是进程:进程是指在系统中正在运行的一个应用程序,每个进程之间是独立,且运行在其专用且受保护的内存空间内。如开打的一个exe就是一个进程。
什么是线程:进程要想执行任务,必须得有线程。每个进程至少有一个线程,线程是进程的基本执行单元,一个进程的所有任务都是在线程中执行。同一个进程的各个线程可以共享该进程所拥有的资源,这一点很关键,我们可以利用这一点来做到线程之间的通信。
一个进程好比一个工厂,工厂要生产东西就必须要有生产流水线。如果一个工厂只有一个躯壳而没有生产流水线是无法生产出产品的。这也就是为什么一个进程至少有一个线程的原因。但是往往一条生产流水线的工作效率是很有限,需要为工厂多增加几条生产流水线。即一个进程启动多个线程了完成任务。属于工厂的资源,任何一条流水线都可以使用,也就是一个进程的资源各个线程都可以共享。就好比公司的饮水机,是属于公司所有不属于某一个线程所有,一个员工表示一个线程的话,那么每个员工都可以去饮水机打水。
include<stdlib.h> include<Windows.h> void main() { MessageBoxA(0,''ABC",''QWE",0);//弹出一个对话框 MessageBoxA(0,''ABC",''QWE",0); MessageBoxA(0,''ABC",''QWE",0); MessageBoxA(0,''ABC",''QWE",0); MessageBoxA(0,''ABC",''QWE",0); }
上面一段代码,目的是弹出5个对话框,没有做任何特殊的处理。我们运行这段代码就是运行一个进程,且是单线程的。先弹出一个对话框,点击确定再弹出第二个…以此类推一共弹出5个。
现在我们用多线程并发来实现,同时弹出5个对话框的功能。也就是说我们需要5个线程来完成这个任务,一次性给它搞定。
include<stdlib.h> include<process> //多线程头文件 include<Windows.h> void run(void *p)//参数为一个空指针,可以指向任何类型 { MessageBoxA(0,''ABC",''QWE",0);//弹出一个对话框 } void main() { for(int i = 0;i<5;i++) { _beginthread(run,0,NULL);//使用一个for循环启动5个线程 //第一个参数为线程要执行任务的函数指针 //第二个参数为线程栈的大小,0表示使用默认值,即一个栈的默认大小为1M //这个大小值是由编译器维护了,如果需要更大的栈空间,我们可以手动修改。 //第三个参数表示任务函数的传入参数。 } }
运行结果如图所示:
我们成功的使用多线程并发一次性完成5个窗口的弹出。通过系统工具查看一下该进程与线程的状态:
蓝色为我们该程序的进程,我们看到该进程里面有6个线程,莫慌,从上往下第三个线程为进程的主线程,它负责创建其他的子线程。就是这样子。
我们来进阶一下多线程
include<stdio.h> include<stdlib.h> include<process> void gogo(void *p) { int i = 0; while(1)//启动一个while循环,每次循环间隔1秒,i自加一次,i>10时结束当前线程 { if(i>10) { printf("%d",i); _endthread();//结束当前线程,与beginthread()正好相反 } i++ Sleep(1000); } } void time(void *p) { int i = 0; while(1) { char str[100] = {0};//定义一个字符数组,长度100,初始化为0 sprintf(str,"title 当前时间第%d",i);//将字符向str输出,即将字符写入到str i++; system(str);//系统执行,改变黑框的标题,显示出时间 Sleep(1000);//每次循环间隔一秒钟 } } void main() { _beginthread(time,0,NULL);//同样启动多线程来执行time函数 for(int i = 0;i<5;i++) { _beginthread(gogo,0,NULL); Sleep(1000);//延迟1秒创建一个线程 } }
花两分钟就阅读完上面代码,我们要的事情就是两件,启动一个子线程执行time函数。for循环启动5个子线程,执行gogo函数。time函数负责在黑框标题显示时间,gogo函数在运行到第11秒的时候结束自己当前的线程并且打印i的值,那么就是有5个gogo函数被执行,打印,结束。main函数里面延迟1秒创建一个线程,所以结束线程的时候就是一秒钟结束一个。
如图所示,我们可以看出多线程直接是并发的,且他们的执行相互不影响,各自己做自己的事情即可。如果我们想让自己创建的多线程不并发,即串行执行。也就是说多个线程,一个执行完再到下一个线程成开始执行,以此类推。我们只需要修改main函数里面for循环的代码如下
for(int i = 0;i<5;i++) { HANDLE hd = _beginthread(gogo,0,NULL);//使用hd接收开启线程的返回值为线程的编号其实是一个整数类型,HANDLE也是一种数据类型。 WaitForSingleObject(hd,INFINITE);//阻塞线程,等待上一个线程执行完毕再开始下一个线程 Sleep(1000);//延迟1秒创建一个线程 }
所以我们知道多线程的调度有两中模式,一种并发,一种串行。
我们可以使用多线程并发来解决很多问题,如在一个大数据下查找一个数。将数据集分成10份,给10个线程并发查找。这样岂不是快很多。当其中一线程找到之后还可以通知其他还在找的线程不用再找了,我已经找到了。
下回分解。