操作系统 线程的创建

首先了解一下进程和线程

进程:执行任务的独立集合  分配资源的基本单位
线程:隶属于进程的一部分  分配cpu的基本单位(轮片时间片的基本单位)
线程的运行方式: 1.并发 多个执行命令交替执行
                         2.并行 多个执行命令同时执行
例如 :
        a=0;
        两个线程执行 a++ 
        并发执行:a=2
        并行执行:a=1

线程的组成部分:
1.线程栈(堆栈区):用来存放线程的临时的 局部的资源
2.内核对象:计数器(2) (句柄关闭-1,线程退出-1)  挂起计数器   信号(无):如果线程退出 会变成有信号  ;不退出  无信号

线程的挂起和恢复:
由挂起计数器控制  计数为0时才真正的执行挂起和恢复



我们想实现三个按钮控制进度条的界面

 

 这里我们想要实现

按下go按钮  进度条增长

按下pause按钮  进度条暂停

按下stop按钮  进度条清空 杀死进程


创建线程的函数:
 
CreateThread(0,//线程安全属性
                 0,//线程栈的大小 默认1MB
                 &TheradProc,//线程函数
                 this,//线程参数
                 0,//创建标志 0 立刻运行  CREATE_SUSPENDED 挂起
                 0//线程id
                );

其中 线程函数TheradProc():  我们想要的功能  要在线程函数里实现

先展示主界面包含什么

#ifndef WIDGET_H
#define WIDGET_H
#include<windows.h>
#include <QWidget>
#include<QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


signals:
    void signalSetValue(int );//线程函数里发射的信号  用于修改进度条
public slots:
    void slotSetValue(int );//线程函数里发射的信号的槽函数 修改进度条
private slots:
    void on_pushButton_clicked(); //go按钮槽函数

    void on_pushButton_2_clicked();//pause按钮槽函数

    void on_pushButton_3_clicked();//stop按钮槽函数

private:

    Ui::Widget *ui;
public:
    HANDLE hTherad;//用于记录线程的句柄
    bool Mark;//stop按钮用到  用于控制线程的结束
};
#endif // WIDGET_H

我们首先为按钮go添加一个槽函数

void Widget::on_pushButton_clicked()
{

    //创建线程
    if(! hTherad)
    {
        Mark=true;
        hTherad= CreateThread(
                     0,//线程安全属性
                     0,//线程栈的大小 默认1MB
                     &TheradProc,//线程函数
                     this,//线程参数
                     0,//创建标志 0 立刻运行  CREATE_SUSPENDED 挂起
                     0//线程id
                    );
    }
    else
    {
        ResumeThread(hTherad);
        //恢复线程

        //SuspendThread(hTherad);  挂起线程 1
        //SuspendThread(hTherad);  挂起线程 2
        //ResumeThread(hTherad);   恢复线程 1
        //ResumeThread(hTherad);   恢复线程 0

    }


}

在槽函数中我们添加一个线程

同时将我们的线程的句柄赋给hTherad 

之后我们就可以通过hTherad对线程进行一些操作了

将创建线程的函数: CreateThread的参数 :全局线程函数TheradProc()定义出来

在TheradProc函数中 我们要对进度条进行操作 

在全局函数中不识别当前的界面ui  不能直接对界面上的空间内进行操作

可以通过连接信号和槽进行间接操作

同时 我们又对其加了一个判断条件  如果线程已经被创建出来  就无须再进行创建了

只需要让进度条动起来就行

 else
    {
        ResumeThread(hTherad);
        //恢复线程

        //SuspendThread(hTherad);  挂起线程 1
        //SuspendThread(hTherad);  挂起线程 2
        //ResumeThread(hTherad);   恢复线程 1
        //ResumeThread(hTherad);   恢复线程 0

    }

这里演示了挂起线程和恢复线程

如:挂起n次线程  需要恢复n次线程才能让线程动起来  

DWORD WINAPI TheradProc(LPVOID lpParameter)
//线程函数是一个全局函数  不能识别ui  所以线程参数 定义为Widget*类型
{
   Widget*wig=(Widget*)lpParameter;


        for (int  i=0;i<=100&&wig->Mark==true;i++) {

            //发送信号  传i的值用于修改
            emit wig->signalSetValue(i);
            Sleep(100);//每隔100毫秒执行一次
        }


   return 0;
}

槽函数

void Widget::slotSetValue(int  i)
{

    //对进度条修改
    ui->progressBar->setValue(i);


}

在Widget界面的构造函数进行信号的连接

 connect(this,&Widget::signalSetValue,this,&Widget::slotSetValue);
到这里我们的go按钮就完成了

接下来开始编写我们的pause按钮的功能

对pause按钮添加一个槽函数

void Widget::on_pushButton_2_clicked()
{
    SuspendThread(hTherad);
    //挂起线程
}

只需要将线程挂起就可以达到暂停的作用

接下来 stop按钮

这里我们有三种方法来结束线程

1.正常结束  

Mark=false;

 if(hTherad)
    {
       

        CloseHandle(hTherad);
        hTherad=NULL;
    }
    ui->progressBar->setValue(0);

标记赋值为false

如果句柄不等于空  就把句柄回收 

缺点 :无法确保线程一定会结束  只是把句柄回收了 
2.强制杀死

Mark=false;

 if(hTherad)
    {
      
                TerminateThread(hTherad,-1);

        CloseHandle(hTherad);
        hTherad=NULL;
    }

一定会使进程结束

缺点:当进程在开辟空间的过程中   突然被杀死  那么开辟的空间不会被回收  并且空间的锁无法访问  造成内存泄露

void Widget::on_pushButton_3_clicked()
{

    //正常退出
    Mark=false;
    //强制杀死
    //TerminateThread(hTherad,-1);
    //3.能正常退出  则正常退出 如果不能  则强制杀死
    //(线程正常退出时会发送一个信号  如果信号=WAIT_TIMEOUT则视为正常退出)
    if(hTherad)
    {
        if(WAIT_TIMEOUT==WaitForSingleObject(hTherad,100))
                TerminateThread(hTherad,-1);

        CloseHandle(hTherad);
        hTherad=NULL;
    }
    ui->progressBar->setValue(0);

}

3.结合的方式结束(一般我们用)

//正常退出
    Mark=false;
   
    //(线程正常退出时会发送一个信号  如果信号=WAIT_TIMEOUT则视为正常退出)
    if(hTherad)
    {
        if(WAIT_TIMEOUT==WaitForSingleObject(hTherad,100))
                TerminateThread(hTherad,-1);

        CloseHandle(hTherad);
        hTherad=NULL;
    }
    ui->progressBar->setValue(0);

完整代码如下

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值