进程:执行任务独立的集合,分配资源的基本单位
线程:隶属于进程的一部分,分配CPU的基本单位(轮换时间片的基本单位)
线程的运行方式:1.并发:多个执行命令交替执行
2.并行:多个执行命令同时执行
线程组成部分:1.线程区(堆栈区),用来存放线程所需要的临时的、局部资源
2.内核对象:计数器(2) 关闭句柄-1 线程退出-1
挂起计数器
信号
无信号:线程存在
有信号:线程不存在
线程挂起和恢复:
SuspendThread(m_hThread);挂起线程
ResumeThread(m_hThread);恢复线程
退出方式:先退出 若不能退出 则杀死
线程的局部存储(TLS)
线程栈私有 堆是共有的
同一进程中的线程间通信 :全局变量 信号和槽 事件
跨进程通信: 事件
用户线程 内核线程
单线程:洗衣服 做饭
多线程:一起来
提高工作的密集度来提高效率
1-1
n-1
n-m(n < m)
多线程访问共享资源并发问题
解决方案:线程同步
方式:1.原子访问:同一时刻只允许一个线程访问资源 volatile 防止编译优化,对特殊地址的稳定访问 直接操作内存
2.临界区(关键段)(用户模式下的线程同步):同一时刻只允许一个线程访问代码段
1)直接阻塞
2)旋转锁:如果发现关键段里面有其他线程,他会等待一段时间,时间内若关键段的线程出现在锁外,他就进得去,否则处于死锁状态
3)非阻塞:能进就进 不耽误干别的
3.内核对象:同一时刻只允许一个线程访问代码段
1)互斥量 同一时刻只允许一个线程访问代码段 初始拥有权
2)事件 同一时刻只允许一个线程访问代码段 人工
3) 信号量 同一时刻允许指定个数的线程访问代码段
内核对象与关键段的区别:1.安全灵活:内核对象 (任意控制阻塞时间)(当拥有内核对象的这个线程被杀死,这个内核对象会被释放,关键段不可以,若被锁了,锁会被一直占用)
2.作用范围:内核对象可以跨进程 临界区:同一进程
3.效率:临界区
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <windows.h>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public:
QTimer* pTimer;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
signals:
void signalSetValue(int);
public slots:
void SlotSetValue(int);
private:
Ui::Widget *ui;
public:
HANDLE m_hThread;
bool m_bFlag;
};
#endif // WIDGET_H
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
m_bFlag = true;
m_hThread = nullptr;
ui->setupUi(this);
connect(this,&Widget::signalSetValue,this,&Widget::SlotSetValue);
}
Widget::~Widget()
{
delete ui;
}
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
Widget* pThis = (Widget*)lpParameter;
for(int i; i <= 100 && pThis->m_bFlag == true; i++)
{
//向主线程发送信号i
emit pThis->signalSetValue(i);
//pThis->ui->progressBar->setValue(i);
Sleep(100);
i%=100;
}
return 0;
}
void Widget::on_pushButton_clicked()
{
if(!m_hThread)
{
m_bFlag = true;
m_hThread = CreateThread(0,//线程安全属性
0,//线程栈的大小
&ThreadProc,//线程函数
this,//线程参数
0,//创建标志 0 立即运行 CREATE_SUSPENDED 挂起
0 //线程Id
);
}
else
ResumeThread(m_hThread);
// SuspendThread(m_hThread);//挂起线程
// ResumeThread(m_hThread);//恢复线程
}
void Widget::SlotSetValue(int value)
{
ui->progressBar->setValue(value);
}
void Widget::on_pushButton_2_clicked()
{
SuspendThread(m_hThread);//挂起线程
}
void Widget::on_pushButton_3_clicked()
{
//1.正常退出
m_bFlag = false;
//2.强制杀死
//TerminateThread(m_hThread,-1);
//如果能正常退出就正常退出,若不能则强制杀死
//如何判断是否退出?--若线程为无信号代表线程存在,则强制杀死
if(m_hThread)
{
if(WAIT_TIMEOUT == WaitForSingleObject(m_hThread,100))
{
TerminateThread(m_hThread,-1);
}
CloseHandle(m_hThread);
m_hThread = nullptr;
}
ui->progressBar->setValue(0);
}