C++ 如何销毁进程

news/2025/2/22 14:01:34

从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();
}

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


http://www.niftyadmin.cn/n/5862355.html

相关文章

vue 学习-vite api.js

/** 整机管理 * */ // 整机分类 列表 export const wholeMachineServersType params > ajaxGet({url: wholeMachine/serverstype/,params}) // 整机分类 新增 export const wholeMachineServersTypeAdd params > ajaxPost({url: wholeMachine/serverstype/,params}) /…

深度学习数据集

1 huggingface datasets 需要先安装 datasets库 pip install datasets 用coco数据集举例&#xff0c;我们可以搜索coco&#xff0c;然后通过页面右侧的use this dataset或者是 clone respository来获取数据集 https://huggingface.co/datasets/phiyodr/coco2017 huggingface的…

【深度学习】矩阵的理解与应用

一、矩阵基础知识 1. 什么是矩阵&#xff1f; 矩阵是一个数学概念&#xff0c;通常表示为一个二维数组&#xff0c;它由行和列组成&#xff0c;用于存储数值数据。矩阵是线性代数的基本工具之一&#xff0c;广泛应用于数学、物理学、工程学、计算机科学、机器学习和数据分析等…

跳跃游戏(力扣55)

题目问是否可以跳到数组最后一个下标&#xff0c;有的同学可能会思考如何模拟跳跃这个操作&#xff0c;但这是比较困难的&#xff0c;很容易把自己绕进去。可以换一种思路&#xff0c;我们不需要知道具体是如何跳到最后一个下标的&#xff0c;而是找到最大的跳跃范围。如果该跳…

应用层的协议-http/https的状态码

1xx&#xff1a;表示临时响应&#xff0c;需要操作者继续操作 2xx&#xff1a;成功&#xff0c;操作被成功接受并处理 3xx&#xff1a;一般是重定向问题 4xx&#xff1a;客户端的问题 5xx&#xff1a;服务端的问题 1xx&#xff1a; 100: 表示服务器收到客户端的第一部分请…

基于WebRTC与AI大模型接入EasyRTC:打造轻量级、高实时、强互动的嵌入式音视频解决方案

随着物联网和嵌入式技术的快速发展&#xff0c;嵌入式设备对实时音视频通信的需求日益增长。然而&#xff0c;传统的音视频解决方案往往存在体积庞大、实时性差、互动体验不佳等问题&#xff0c;难以满足嵌入式设备的资源限制和应用场景需求。 针对以上痛点&#xff0c;本文将介…

Android:权限permission申请示例代码

Android应用项目每次最开始都要进行权限申请&#xff0c;贴一下权限申请的示例代码&#xff0c;方便后续Ctrl CV使用 1.AndroidManifest.xml 配置要申请的权限 <uses-permission android:name"android.permission.READ_CONTACTS" /> <uses-permission and…

BUUCTF-Web方向16-20wp

目录 [极客大挑战 2019]PHP[ACTF2020 新生赛]BackupFile[RoarCTF 2019]Easy Calc[极客大挑战 2019]BuyFlag[BJDCTF2020]Easy MD5 [极客大挑战 2019]PHP 由内容提示应该存在源码备份&#xff0c;常见的如下&#xff0c;一个个尝试 后缀&#xff1a;tar tar.gz zip rar 名字&am…