文章目录
- 进程(process)
- 线程(Thread)
- 创建线程
进程(process)
在任务管理器中能看到进程Tab页下,将所有进程分为三类:
- 应用:打开的正在运行的软件。
- 后台进程:隐藏到后台,悄悄的运行。
- windows进程:操作系统启动、运行需要依赖的各种服务
各种软件、进程是依附在操作系统上运行的。
程序是 存在存储器里面的可执行代码,当我们双击快捷方式时,操作系统就会将代码从存储器中取出来开始执行,并且 给每一个进程分配一个PID。windows操作系统上的应用程序有的是可以开启多个 的,比如说文件夹、浏览器等,有的应用程序 只允许开启一个,比如说 电脑版的微信。手机系统上的APP一般只允许开启 一个。
进程概念:是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立的基本单元,是应用程序运行的载体。
进程是一种抽象的概念,从来没有统一的标准定义。
进程组成:程序、数据集合、进程控制块。
进程具有4个特征:
- 动态性:进程是程序的一次执行过程,是临时的,有生命周期的,是动态产生,动态消亡的。
- 并发性:任何进程都可以同其他进程一起并发执行。
- 独立性:进程是系统进行资源分配和调度的一个独立单元。
- 结构性:进程由程序,数据和进程控制块三部分组成。
应用程序和进程间的关系:从任务管理器的详细信息页面可以看出,一个应用程序可以启动多个进程,PID(part ID)是进程唯一标识符,就像人的身份证号。一个应用程序 下的多个进程是树形结构,PID最小的数是根节点。在某一个进程上鼠标右键有一个结束进程树的选项,如果你选择杀死根节点的进程树,将会杀死所有子节点的进程。
线程(Thread)
在早期的操作系统中并没有线程的概念,进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位。后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了,于是就发明了线程。
线程概念:cpu能够进行调度、分配 、执行、运算的最小基本单位,是程序执行中一个单一的顺序控制流程。一个进程可以有一个或多个线程,各个线程之间共享进程的内存空间。
- 进程类似于工厂,是系统分配 资源的基本单元,线程类似于工厂中的工人,是cpu调度和执行工作的基本单元。
- 一个进程由一个 或多个线程组成。
- 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)。
- 调度和切换:线程上下文切换比进程上下文切换要快得多。
为了更快速的完成任务,或者某些场景需要同时做多件事情,就需要使用线程,因为线程可以“同时”执行任务。
这里希望先显示进程 间的切换,再显示线程
- 串行:按照顺序,一个执行完再执行下一个。
- 并行:同一个时刻,指同时执行。
- 并发:在同一个时间间隔内发生,指相同的时间间隔,交替执行。
在单线程下,采用串行的方式执行。
大部分操作系统的任务调度是采用轮换时间片的抢占式调度方式,一个线程执行一小段时间后暂停休息并等待着被唤醒,下一个线程被唤醒并开始执行,每个线程交替轮流执行。线程执行的一小段时间叫做时间片。
由于CPU的执行速度非常快,时间片非常短,在各个线程之间快速地切换,给人的感觉是多个线程在“同时进行”,这就是常说的并发。
线程的状态:
- 新生态:创建出新的线程对象。
- 就绪态:创建出线程后,进入就绪态,会将线程添加到就绪队列中,等待分配到CPU时间片,就会进入到运行状态。
- 运行态:运行态的线程如果时间片用完后,就会再次进入就绪状态,一般来说就绪态和运行态不需要人为参与,由操作系统进行调度,如果遇到sleep、wait、suspend、IO请求时,就会进入阻塞态。
- 阻塞态(挂起状态):一个正在运行的线程在某些特殊情况下,如被人为挂起 或执行耗时的I/O操作时,会让出CPU的使用权并暂时中止自己的执行,进入阻塞状态,处于阻塞状态的线程,就不能进入排队队列。只有当引起阻塞的原因被消除后 ,线程才可以转入就绪状态。当恢复线程,完成IO操作、等到资源,就会进入就绪状态。
- 销亡态:线程正常执行结束、因异常退出、被强制终止,该进程结束生命周期。
注意:
- 线程必须通过就绪态分配到时间片才能进入运行状态,而不能直接进入运行状态。
- 就绪状态无法进入阻塞状态。
- 其他状态的线程可直接进入销亡态。
创建线程
创建一个Qt控制台项目,在window下使用API函数CreateThread,Header:#include<windows.h>
::CreateThread(nullptr/*默认的安全属性*/,
0/*windows 默认1M*/,
&ThreadProc/*线程函数的地址*/,
&n/*线程函数的参数*/,
0/*0:立即运行 ,SUS_PEND 挂起*/,
nullptr/*线程ID*/);
通过寻找第三个参数可以找到线程函数
DWORD WINAPI ThreadProc (LPVOID lpThreadParameter){
int nn = *(int*)lpThreadParameter;
for(int i=0;i<nn;i++){
qDebug()<<"挣钱----"<<i;
Sleep(1000);
}
return 0;
}
在主函数中也写一段类似的循环
for(int i=0;i<20;i++){
qDebug()<<"-------------------睡觉:"<<i;
Sleep(1000);
}
通过测试我们可以发现,我们是创建了一根新的线程,而不是简单的调用线程函数