c++ qt–线程(一)(第八部分)
一.进程(Process)
在任务管理器中的进程页下,可以看到进程,任务管理器将进程分为了三类,应用、后台进程、window进程
应用:
打开的正在运行的软件
后台进程:
隐藏在后台,“悄悄”的运行
window进程:
操作系统启动、运行需要依赖的各种服务
1.进程的概念
是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立的基本单元,是应用程序运行的载体
进程是一种抽象的概念,从来没有统一的标准定义
2.进程的组成
进程由程序、数据集合、进程控制块三部分组成
3.进程的4个特征
1.动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生。动态消亡的
2.并发性:任何进程都可以同其他进程一起并发执行
3.独立性:进程是程序进行资源分配和调度的一个独立单元
4.结构性:进程由程序、数据集合、进程控制块三部分组成
4.应用程序和进程间的关系
一个应用程序下的多个进程是树形结构。
PID是进程的唯一标识符,PID最小的数是根节点
二.线程(Thread)
1.线程的概念
cpu能够进行调度、分配、执行、运算的最小的基本单位。是程序执行中一个单一的顺序控制流程,一个进程可以有一个或多个线程,各个线程之间共享进程的内存空间
2.线程的串行,并行和并发
串行:按照顺序。一个执行完再执行下一个
并行:同一个时刻,同时进行
并发:再同一个时间间隔内发生,指相同的时间间隔,交替执行
在单线程下,采用串行的方式执行
大部分操作系统的任务调度是采用轮换时间片的抢占式调度方式,一个线程执行一小段时间后暂停休息并等待着被唤醒,下一个线程被唤醒并开始执行,每个线程交替轮流执行,。线程执行的一小段时间叫做时间片
由于cpu的执行速度非常快,时间片非常短,在各个线程之间快速地切换,给人的感觉就是多个线程在“同时进行”,这就是常说的并发
3.线程的状态
1.新生态:创建出新的线程对象
2.就绪态:创建出线程后,进入就绪态,会将线程添加到就绪队列中,等待分配到cpu时间片,就会进行运行状态
3.运行态:运行态的线程如果时间片用完后,就会再次进入就绪状态,一般来说就绪态和运行态不需要认为参与,由操作系统进行调度,如果遇到sleep、wait、suspend、IO请求时就会进入阻塞态
4.阻塞态(挂起状态):一个正在运行的线程在某些特殊情况下,如被认为挂起或执行好事的I/O操作时,会让出cpu的使用权并暂时中止自己的执行,进入阻塞状态,处于阻塞状态的线程,就不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。当恢复线程,完成IO操作、等到资源,就会进入就绪状态
5.销亡态:线程正常执行结束、因异常退出、被强制终止,该线程结束生命周期
注意:
1.线程必须通过就绪态分配到时间片才能进入运行状态,而不能直接进入运行状态
2.就绪状态无法进入阻塞状态
3.其他状态的线程可直接进入销亡态
三.使用QT创建线程(进一步理解线程)
1.创建一个控制台窗口
2.创建线程
1.使用的头文件为
#include <windows.h>
2.创建线程
在main.cpp中的mian函数中写下面代码
int n=20;
//创建一个子线程,主线程可以看作是main函数 的执行
HANDLE handle=::CreateThread(nullptr/*使用默认的安全属性*/,//线程的安全属性,返回的是线程句柄,这里我们用线程句柄接一下
0//用默认的线程栈大小window(1M)
,&ThreadProc//线程函数
,&n//线程函数传递的参数
,0//创建线程后,0:立即执行,CREATE_SUSPENDED:挂起
,nullptr//返回线程ID
);
3.线程函数
在main.cpp中写下面代码
DWORD (WINAPI/*调用约定*/ ThreadProc) (LPVOID/* void* */ lpThreadParameter){
return 0;//表示当前函数正常退出
}
4.通过输出观察两个线程的执行
主线程
int n=20;
//创建一个子线程,主线程可以看作是main函数 的执行
HANDLE handle=::CreateThread(nullptr/*使用默认的安全属性*/,//线程的安全属性,返回的是线程句柄,这里我们用线程句柄接一下
0//用默认的线程栈大小window(1M)
,&ThreadProc//线程函数
,&n//线程函数传递的参数
,0//创建线程后,0:立即执行,CREATE_SUSPENDED:挂起
,nullptr//返回线程ID
);
//进行一个输入,看主线程与子线程的关系
for(int i=0;i<20;i++){
qDebug()<<"--------------------------------主人 睡了"<<i;
Sleep(1000);
}
子线程
DWORD (WINAPI/*调用约定*/ ThreadProc) (LPVOID/* void* */ lpThreadParameter){
//进行一个输入,看主线程与子线程的关系
int n=*(int*)lpThreadParameter;//将void*强转为int*最后取其中的值
for(int i=0;i<n;i++){
qDebug()<<"仆人在挣钱"<<i;
Sleep(1000);
}
return 0;//表示当前函数正常退出
}
5.线程的挂起、恢复操作(这里对子线程挂起和恢复操作)
主线程
在main.cpp中的mian函数中写下面代码
int n=20;
HANDLE handle=::CreateThread(nullptr,
0
,&ThreadProc
,&n/
,CREATE_SUSPENDED//这里改为了CREATE_SUSPENDED,挂起
,nullptr
);
for(int i=0;i<20;i++){
if(i==3){
//返回的是恢复或挂起之前 挂起计数器的值,当挂起计数器的值为0时,线程才能继续运行
//挂起几次,就得恢复几次,线程才能继续运行
DWORD count=::ResumeThread(handle);//恢复某一个线程运行
qDebug()<<"count111 "<<count;
}
if(i==7){
DWORD count=::SuspendThread(handle);
qDebug()<<"count222 "<<count;
}
if(i==10){
DWORD count=::SuspendThread(handle);
qDebug()<<"count333 "<<count;
}
if(i==13){
DWORD count=::ResumeThread(handle);
qDebug()<<"count444 "<<count;
}
if(i==15){
DWORD count=::ResumeThread(handle);
qDebug()<<"count555 "<<count;
}
qDebug()<<"--------------------------------主人 睡了"<<i;
Sleep(1000);
}
子线程
在main.cpp中写下面代码
DWORD (WINAPI/*调用约定*/ ThreadProc) (LPVOID/* void* */ lpThreadParameter){
//进行一个输入,看主线程与子线程的关系
int n=*(int*)lpThreadParameter;//将void*强转为int*最后取其中的值
for(int i=0;i<n;i++){
qDebug()<<"仆人在挣钱"<<i;
Sleep(1000);
}
return 0;//表示当前函数正常退出
}
6.线程的关闭和退出操作()
定义两个关于退出标志
bool isTreadQuit=false;//退出的标志,这里初始是不退出
bool isAlreadyQuit=false;//告诉主线程退出了,这里初始是不告诉
主线程
在main.cpp中的mian函数中写下面代码
int n=20;
//创建第一个线程时也会创建内核对象,这时使用计数默认+1
HANDLE handle=::CreateThread(nullptr,
0
,&ThreadProc
,&n/
,0//这里改为了0,立即执行
,nullptr
);
for(int i=0;i<20;i++){
qDebug()<<"--------------------------------主人 睡了"<<i;
if(i==6){
isTreadQuit=true;
qDebug()<<"通知子线程退出";
break;
}
//第一种 一直等子线程退出的标记
//while(1){
// if(isAlreadyQuit){
// qDebug()<<"收到子线程退出的标记了";
// break;
// }
// Sleep(1000);
//}
//第二种,设置等待时间等子线程退出,这里设置的是7秒
DWORD flag=WaitForSingleObject(handle,7000);//这里的参数单位是毫秒
if(flag==WAIT_OBJECT_0){//在设定的等待时间内,子线程正常退出了
qDebug()<<"子线程退出了";
}else if(flag==WAIT_TIMEOUT){//在设定的等待时间内,子线程没有退出,等待超时了
qDebug()<<"等待超时,强制杀死线程";
::TerminateThread(handle,-1);//强制杀死子线程,有风险的方式
}
if(handle){
::CloseHandle(handle);//关闭句柄,使用计数-1,当使用计数减为0的时候系统就会回收内核对象·
}
handle=nullptr;
Sleep(1000);
}
子线程
在main.cpp中写下面代码
DWORD (WINAPI/*调用约定*/ ThreadProc) (LPVOID/* void* */ lpThreadParameter){
int n=*(int*)lpThreadParameter;
while(!isTreadQuit){
qDebug()<<"仆人在挣钱";
Sleep(1000);
}
//第一种
//isAlreadyQuit=true;
return 0;
}