当前位置: 首页 > news >正文

C++ 如何销毁进程

从C++11开始,C++STL开始支持线程,
先看一个C++11 thread的例子

#include "stdafx.h"
#include <thread>
#include <chrono>
#include <iostream>
#include <functional>
#include <string>

bool isRunning = true;
std::thread* tptr;
uint8_t* byte_ptr;
constexpr size_t kLen = 10;

static void ShowMem(uint8_t* p, const size_t size = kLen)
{
	for (size_t i = 0; i < kLen; ++i)
	{
		printf("%02x", p[i]);
	}
	printf("\n");
}

void thread_func()
{
	static int i = 0;
	while (isRunning)
	{
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
	std::cout << "thread_func finished" << std::endl;
}

void Shell_Thread()
{
	std::string input;
	while (1)
	{
		std::cin >> input;
		if (input == "exit")
		{
			exit(EXIT_SUCCESS);
		}

		if (input == "showmem")
		{
			ShowMem(byte_ptr, sizeof(std::thread));
			continue;
		}
		if (input == "release")
		{
			delete tptr;
			continue;
		}
	}
}

int main()
{
	do {
		std::thread t(Shell_Thread); t.detach();
	} while (0);

	tptr = new std::thread(thread_func);
	tptr->detach();
	byte_ptr = reinterpret_cast<uint8_t*>(tptr);
	while (1)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
}


在windows平台编译成debug版本,然后运行
先查看任务管理器
在这里插入图片描述

线程数是3
main函数一个主线程,Shell_Thread,thread_func 分别一个线程,总共3个线程

在控制台输入release 回车,然后输入showmem回车

release
showmem
dddddddddddddddddddd

可以看到输出dddd...
window平台,debug模式下free掉的内存会被系统填充成0xdd
销毁了线程并且windows也没有报错。
在任务管理器下面可以看到
在这里插入图片描述

tptr 所指向的thread对象销毁了,但thread_func 这个函数仍然在系统中运行。

现在将if (input == "release")分支下delete tptr;这一句换成isRunning = false;
重复上面执行一下可以看到

showmem
0000000000000000fdfd
release
thread_func finished
showmem
0000000000000000fdfd

在这里插入图片描述
线程数变成了2,但是tptr指向的内存没被free,内存泄露了。
std::cout << "thread_func finished" << std::endl; 这个语句后面加上一句delete tptr可以解决问题,但明显不会是一个好的方式。
需要自行包装一下Thread,在线程运行结束后自我销毁,或者由第三个对象在判断线程运行结束后再销毁线程对象。


现在看Qt下面一个多线程的例子

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QDebug>
#include <iostream>

class MyWrap
{
public:
	explicit MyWrap();
	virtual ~MyWrap();
	bool isRunning;
	QThread* t;
};

class MyThread : public QThread {
public:
	explicit MyThread(MyWrap*);
	void run() Q_DECL_OVERRIDE;
	MyWrap* m_wrap;
};

class MyShell : public QThread {
public:
	void run() Q_DECL_OVERRIDE;
};


MyWrap *wrap_ptr;
QThread *tptr;
uint8_t* byte_ptr;
constexpr size_t kLen = 10;

static void ShowMem(uint8_t* p, const size_t size = kLen)
{
	QString str;
	for (size_t i = 0; i < kLen; ++i)
	{
		str += QString::number(p[i], 16);
	}
	qDebug() << str;
}


int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	do {
		QThread *shell = new MyShell();
		shell->start();
	} while (0);
	wrap_ptr = new MyWrap();
	tptr = wrap_ptr->t;
	byte_ptr = reinterpret_cast<uint8_t*>(tptr);
	tptr->start();
	return a.exec();
}


void MyShell::run()
{
	std::string input;
	while (1)
	{
		std::cin >> input;
		if (input == "exit")
		{
			QCoreApplication::exit(0);
			return;
		}

		if (input == "showmem")
		{
			ShowMem(byte_ptr, sizeof(MyThread));
			continue;
		}
		if (input == "release")
		{
			delete wrap_ptr;
			continue;
		}
	}
}


MyThread::MyThread(MyWrap* wrap)
	:QThread(),m_wrap(wrap)
{

}

void MyThread::run()
{
	while (m_wrap->isRunning)
	{
		QThread::sleep(1);
	}
	qDebug() << __FUNCTION__ << " end";
	this->deleteLater();
}

MyWrap::MyWrap()
	: isRunning(true)
{
	this->t = new MyThread(this);
	this->t->start();
}

MyWrap::~MyWrap()
{
	isRunning = false;
	
}

在上面例子中把m_wrap->isRunning换成一个全局的变量,程序可以按照预期的方向运行。

将MyWrap与MyThread修改成如下

MyWrap::~MyWrap()
{
	isRunning = false;
	this->t->quit();
	this->t->wait();
	delete this->t;
}

void MyThread::run()
{
	while (m_wrap->isRunning)
	{
		QThread::sleep(1);
	}
	qDebug() << __FUNCTION__ << " end";
}

程序也会如期运行。
但MyThread::run中执行太多耗时操作,而MyWrap是界面的操作,将会导致界面长时间卡顿。

将MyWrap与MyThread修改成如下

MyWrap::~MyWrap()
{
	this->t->requestInterruption();
}

void MyThread::run()
{
	while (!this->isInterruptionRequested())
	{
		if (IsBadReadPtr(m_wrap,sizeof(MyWrap))) { break; }
		// read m_wrap-> ....
		QThread::sleep(1);
	}
	qDebug() << __FUNCTION__ << " end";
	this->deleteLater();
}

这样将会优雅的结束线程并销毁线程。

千万不要像下面这样

MyWrap::~MyWrap()
{
	this->t->requestInterruption();
	this->t->deleteLater();
}

这样将会得到一个
在这里插入图片描述

相关文章:

  • 在Windows和Linux平台上使用c++获取文件当前路径
  • [AI相关]Unity的C#代码如何简写
  • 探索JavaScript网页设计的无限可能:从基础到AI集成
  • ChatBox对接DeepSeek R1大模型
  • wordpress企业官网建站的常用功能
  • golang channel底层实现?
  • hot100——11,42
  • python爬虫系列课程3:解决爬虫过程中遇到的编码问题
  • Windows逆向工程入门之调用约定
  • Python logging 库全面指南
  • Skibidus and Fanum Tax (easy version)----Skibidus 和 Fanum 税(简易版)
  • 第四届图像、信号处理与模式识别国际学术会议(ISPP 2025)
  • 利用acme.sh 申请 Google 免费证书
  • 人车检测与计数系统(python+课程设计报告+源代码+数据集)
  • LeetCode 98.验证二叉搜索树
  • vscode远程报错:Remote host key has changed,...
  • 软件安全测试技术系列|跨站脚本攻击(Cross Sites Script)类漏洞攻击方式与防御措施
  • Opencv项目实战:26 信用卡号码识别与类型判定
  • 自动化办公|通过xlwings进行excel格式设置
  • 防火墙综合实验
  • 2025年两岸关系研讨会在上海开幕
  • 重庆大学通报本科生发14篇SCI论文:涉事学生及其父亲被处理
  • 习近平会见塞尔维亚总统武契奇
  • 七大交响乐团“神仙斗法”,时代交响在上海奏出时代新声
  • 外交部答澎湃:美方攻击抹黑中加关系与合作的卑劣图谋不会得逞
  • 胖东来发布和田玉、翡翠退货说明:不扣手续费等任何费用