暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

高效内存池的实现 & C++17 内存池的应用

林元皓 2021-11-01
1810

前言

文章写在了 OpenSSL 密码学 专栏当中,是因为在使用 C++17 内存池时,使用了 OpenSSL 的加解密接口。

因为可以节省了工程配置,所有在 OpenSSLProject 项目中,直接创建了 MemoryPoolProjec 工程。并将 OpenSSL 的头文件和库文件添加到了工程中。

高效内存池的实现

为什么要实现高效内存池?

在服务器程序开发中,需要程序能长期稳定的运行,而 C++ 程序且不说内存泄漏问题,随着不断频繁的 new 和 delete,也会使堆空间的数据碎片化,导致new 和 delete 的效率下降,而影响你开发的程序效率。

而作为一个游戏服务器,要求的更高,无数的玩家不同行为,长期运行有可能几周甚至几个月,直至服务器维护。

由于程序要长时间运行、对速度要求高、对稳定性要求高。因此引入了高效内存池,不能让其程序肆意妄为的 new 和 delete,最终导致堆空间的数据碎片严重,而影响了服务器程序的效率,减少宕机风险。

如何解决频繁的 new 和 delete 问题

不让程序员去 new 和 delete ? 这太不切合实际了,那我们应该怎么做呢 ?

当然有办法,可以重载全局的 new 和 delete

重载全局的 new 和 delete 的好处:

监测内存创建销毁 ,统计和监控泄漏。内存对齐的处理。

当然,我们要做的是实现自己的内存池,然后通过重载全局的 new 和 delete ,来反复使用内存池中的空间。

如何设计一个内存池

先看一下内存池需求:

避免内存碎片提高程序稳定性减少申请内存时间。

看一下内存池设计图:



因此我们需要做的一个大小固定、提前申请、重复利用的内存池。

当我们 new 的时候,可以在内存池中直接找到我们已经申请好的空间进行使用。



代码的实现

内存块结构定义:

MemoryMgr.h 文件:

class    MemoryBlock
{
public:
size_t nRef = 0; // 引用计数
MemoryAlloc* pAlloc = nullptr; // 内存块链表 分配器指针
MemoryBlock* pNext = nullptr; // 下一个内存块指针
bool bPool = false; // 是否使用内存池 如果是 false 会走默认的 malloc 和 free 去申请释放空间
// 通过宏进行 补位,并没有实际意义,只是防止编译器优化,使 MemoryBlock x86 占用 16字节, x64 占用 32 字节
#ifdef _WIN32
//windows x86 or x68
#ifdef _WIN64 //x64
char cReserver[7] = { 0 };
#else //x86
char cReserver[3] = { 0 };
#endif //_WIN64
#else //unix
#ifdef __x86_64__ //x64
char cReserver[7] = { 0 };
#elif __i386__ //x86
char cReserver[3] = { 0 };
#endif
#endif //_WIN32
};

内存分配器实现:

MemoryMgr.h 文件:

class   MemoryAlloc
{
public:
MemoryAlloc()
{
m_pBuf = 0;
m_nInitBlock= 1024;
}
~MemoryAlloc()
{
_freeNotInPool();
/**
* free
*/
if (m_pBuf != 0)
{
::free(m_pBuf);
}
}
/**
* alloc memory
*/
void* allocMemory(size_t nSize)
{
if (m_pBuf == 0)
{
// 程序在第一次 new 的时候会申请内存池,以后便都在内存池中查找空间
_initMemory();
}
MemoryBlock* pReturn = 0;
/**
*
*/
if (m_pHeader == 0)
{
pReturn = (MemoryBlock*)(::malloc(nSize + sizeof(MemoryBlock)));
pReturn->bPool = false;
pReturn->nRef = 1;
pReturn->pAlloc = this;
pReturn->pNext = 0;
}
else
{
/**
* get one node from free list
*/
pReturn = m_pHeader;
m_pHeader = m_pHeader->pNext;
pReturn->pAlloc = this;
pReturn->bPool = true;
assert(pReturn->nRef == 0);
pReturn->nRef = 1;
}
return ((char*)pReturn) + sizeof(MemoryBlock);
}


/**
* free memory function
*/
void freeMemory(void* pMem)
{
char* pCh = (char*)pMem;
MemoryBlock*pMap = (MemoryBlock*)((char*)(pCh - sizeof(MemoryBlock)));
/**
* ref
*/
if (--pMap->nRef != 0)
{
return;
}
if (!pMap->bPool)
{
::free(pMap);
return;
}
pMap->pNext = m_pHeader;
m_pHeader = pMap;
}




/**
* init memory pool
*/
void _initMemory()
{
assert(m_pBuf == 0);


if (m_pBuf != 0 )
{
return;
}
/**
* 计算需要申请的内存大小,其中包含内存头数据大小
*/
size_t nBuf = m_nSize * m_nInitBlock;
/**
* 申请内存
*/
m_pBuf = (char*)::malloc(nBuf);


/**
* 链表头和尾部指向同一位置
*/
m_pHeader = (MemoryBlock*)m_pBuf;
m_pHeader->nRef = 0;
m_pHeader->pAlloc = this;
m_pHeader->pNext = 0;
m_pHeader->bPool = true;
MemoryBlock* pTemp = m_pHeader;


for (size_t i = 1 ;i < m_nInitBlock ; ++ i)
{
char* pBlock = (m_pBuf + m_nSize * i);
MemoryBlock*pMap = (MemoryBlock*)pBlock;
pMap->nRef = 0;
pMap->bPool = true;
pMap->pAlloc = this;
pMap->pNext = 0;
pTemp->pNext = pMap;
pTemp = pMap;
}
}


/**
* 释放所有数据
* 该函数目的是将所有的不在pool中的内存释放掉
*/
void _freeNotInPool()
{
/**
* 将不在内存池中的临时内存删除掉
*/
while(m_pHeader != 0)
{
MemoryBlock* pHeader = m_pHeader;
m_pHeader = m_pHeader->pNext;
if (!pHeader->bPool)
{
::free(pHeader);
}
}
m_pHeader = 0;
}
/**
* 得到当前池中可用的对象数
*/
size_t _getFreeBlock()
{
MemoryBlock* pTemp = m_pHeader;
size_t nSize = 0;
while(pTemp != 0)
{
++nSize;
pTemp = pTemp->pNext;
}
return nSize;
}
protected:
char* m_pBuf;
MemoryBlock* m_pHeader;
size_t m_nInitBlock;
size_t m_nSize;
};


// 通过模版定义,目的可以快速找到 申请不同大小内存空间时,快速找到对应的内存块
template<size_t nBlock,size_t nInitSize>
class MemoryAlloctor:public MemoryAlloc
{
public:
MemoryAlloctor()
{
m_nInitBlock = nInitSize;
m_nSize = nBlock / sizeof(void*) * sizeof(void*) + (nBlock% sizeof(void*) ? sizeof(void*) : 0 );
m_nSize = m_nSize + sizeof(MemoryBlock);
}
};

内存管理类:

MemoryMgr.h 文件:

class   MemoryMgr
{
public:
MemoryMgr(void)
{


init(0, 64, &m_mem64);
init(64,128, &m_mem128);
init(128, 256, &m_mem256);
init(256, 512, &m_mem512);
init(512, 1024, &m_mem1024);
init(1024, 2048, &m_mem2048);
init(2048, 4096, &m_mem4096);
}


~MemoryMgr(void)
{
}
static MemoryMgr& instance()
{
static MemoryMgr sInstance;
return sInstance;
}
/**
* 申请内存
*/
void* alloc(size_t nSize)
{
if ( nSize < sizeof(m_arAlloc)/sizeof(MemoryAlloc*))
{
return m_arAlloc[nSize]->allocMemory(nSize);
}
else
{
char* pMem = (char*)::malloc(nSize + sizeof(MemoryBlock));
MemoryBlock*pBlock = (MemoryBlock*)pMem;
pBlock->bPool = false;
pBlock->nRef = 1;
pBlock->pAlloc = 0;
pBlock->pNext = 0;
return pMem + sizeof(MemoryBlock);
}
}
/**
* 释放内存
*/
void free(void* pMem)
{
char* pCh = (char*)pMem;
MemoryBlock*pMap = (MemoryBlock*)(char*)(pCh - sizeof(MemoryBlock));
if (pMap->bPool)
{
pMap->pAlloc->freeMemory(pMem);
}
else if(--pMap->nRef == 0)
{
::free(pMap);
}
}
/**
* 添加引用计数
*/
void addRef(void* pMem)
{
MemoryBlock*pMap = (MemoryBlock*)((char*)pMem - sizeof(MemoryBlock));
++pMap->nRef;
}


protected:
void init(size_t nBegin,size_t nEnd,MemoryAlloc* pAlloc)
{
for (size_t i = nBegin ;i < nEnd ; ++ i)
{
m_arAlloc[i] = pAlloc;
}
}
protected:
MemoryAlloctor<64,10240> m_mem64;
MemoryAlloctor<128,10240> m_mem128;
MemoryAlloctor<256,10240> m_mem256;
MemoryAlloctor<512,10240> m_mem512;
MemoryAlloctor<1024,10240> m_mem1024;
MemoryAlloctor<2048,10240> m_mem2048;
MemoryAlloctor<4096,10240> m_mem4096;
MemoryAlloc* m_arAlloc[4096];
};

重载全局的 new 和 delete

Alloctor.h

#pragma once




void* operator new(size_t nSize);
void operator delete(void* pMem);
void* operator new[](size_t nSize);
void operator delete[](void* pMem);
void* mem_alloc(size_t nSize);
void mem_free(void* pMem);

Alloctor.cpp

#include "../include/Alloctor.h"
#include "../include/MemoryMgr.h"




void* operator new(size_t nSize)
{
return MemoryMgr::instance().alloc(nSize);
}


void operator delete(void* pMem)
{
MemoryMgr::instance().free(pMem);
}


void* operator new[](size_t nSize)
{
return MemoryMgr::instance().alloc(nSize);
}


void operator delete[](void* pMem)
{
MemoryMgr::instance().free(pMem);
}


void* mem_alloc(size_t nSize)
{
return MemoryMgr::instance().alloc(nSize);
}


void mem_free(void* pMem)
{
MemoryMgr::instance().free(pMem);
}


测试

main.cpp

#include "../include/Alloctor.h"
#include "../include/MemoryMgr.h"
#include <string>




#define OTA_STRING_MAX_LEN 256


///软件信息
typedef struct
{
char productID[OTA_STRING_MAX_LEN]; // 产品ID
char softVer[OTA_STRING_MAX_LEN]; // 软件版本
char url[OTA_STRING_MAX_LEN]; // 下载地址
int iTotalSize; // 总size
char createDateTime[OTA_STRING_MAX_LEN]; // 发布时间
char detileInfo[OTA_STRING_MAX_LEN]; // 详细描述
char englishDetailInfo[OTA_STRING_MAX_LEN]; // 英文详细描述
char sha256[OTA_STRING_MAX_LEN];
}OTA_SoftPackeInfo;


int main(int _Argc, char* argv[])
{


char* data = new char[112];
delete[] data;


OTA_SoftPackeInfo *soft_packe_info = new OTA_SoftPackeInfo();
delete soft_packe_info;


return 0;
}

C++17 内存池的应用

C++17 内存池

在C++17中已经有了内存池,看一下结构图:



memory_resource:这是一个虚基类(接口),表示对内存资源的管理。pool_options:内存池配置。synchronized_pool_resource:memory_resource的子类,具体实现线程安全的内存管理,显然在分配和释放时加有锁。unsynchronized_pool_resource:memory_resource的子类,具体实现非线程安全的内存管理,在单线程时应用时效率高。

使用内存池文件加解密

由于工程需要使用 C++17 ,因此先将工程设置为使用 C++17 :



设计类结构:



XCrypt 类:加解密类XIOStream 类:线程基类,责任链模式、多线程数据传递、内存池注入和空间管理XReadTask 类:文件读取类,继承 XIOStream  读取文件,发送给下一个责任链,需要告知下一个责任链任务结束XCryptTask 类:加解密处理线程,继承 XIOStream  接收 XReadTask 传递数据XWriteTask 类:写入文件现场,继承 IOStream 接收 XCryptTask 发送的加解密数据XFileCrypt 类:处理文件加解密任务,对整体流程的封装

XData.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 数据类
**************************************************************************************************************/


#pragma once
#include <memory>
#include <memory_resource>


class XData
{
public:
~XData();


void* New(long long mem_size);
void Delete();


// 设置实际数据字节数
void set_size(long long s) { data_size_ = s; }
long long size() { return data_size_; }
void* data() { return data_; }
bool end() { return is_end_; }
void set_end(bool e) { is_end_ = e; }


// 创建 XData 智能指针对象
static std::shared_ptr<XData> Make(std::shared_ptr<std::pmr::memory_resource> pool);


private:
XData() {} // 私有 不能自己创建


bool is_end_ = false;
void* data_ = nullptr;
long long data_size_ = 0; // 数据字节数
long long memory_size_ = 0; // 占用空间字节数
std::shared_ptr<std::pmr::memory_resource> memory_pool_;


};

XData.cpp

#include "../include/XData.h"
#include <iostream>




std::shared_ptr<XData> XData::Make(std::shared_ptr<std::pmr::memory_resource> pool)
{
std::shared_ptr<XData> ptr(new XData);
ptr->memory_pool_ = pool;
return ptr;
}




void* XData::New(long long mem_size)
{
if (mem_size <= 0)
{
std::cerr << "XData::New failed! mem_size<=0" << std::endl;
return nullptr;
}
if (!memory_pool_)return nullptr;
data_ = memory_pool_->allocate(mem_size);
this->memory_size_ = mem_size;
this->data_size_ = mem_size;
//cout << "+" << flush;
return data_;
}


void XData::Delete()
{
if (!data_ || !memory_pool_) return;


memory_pool_->deallocate(data_, memory_size_);
data_ = nullptr;
memory_size_ = 0;
data_size_ = 0;
}


XData::~XData()
{
Delete();
}

XCrypt.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 加解密类 DES加密算法
**************************************************************************************************************/


#pragma once


#include <string>
#include <openssl/des.h>


class XCrypt
{
public:
// 初始化秘钥 秘钥最多8位 多余丢弃不足补0
bool Init(std::string password);


// 加密数据,结尾填充补充的大小,加密数据大小如果不是 8、16的倍数
int Encrypt(const char* in_data, int insize, char* out_data, bool is_end = false);
// 解密数据,结尾去掉填充大小
int Decrypt(const char* in_data, int insize, char* out_data, bool is_end = false);


//获取需要填充的数据字节数
int GetPadding(int datasize);
private:
// 存储秘钥
DES_key_schedule key_sch_;
};

XCrypt.cpp

#include "../include/XCrypt.h"
#include <iostream>


bool XCrypt::Init(std::string password)
{
DES_cblock key = { 0 }; // 不足补0
int key_size = password.size();
if (key_size > sizeof(key)) // 多余丢弃
{
key_size = sizeof(key);
}
memcpy(key.bytes, password.c_str(), key_size);
DES_set_key(&key, &key_sch_);
return true;
}




int XCrypt::GetPadding(int datasize)
{
const int block_size = sizeof(DES_cblock);
int padding = block_size - datasize % block_size;
if (padding == 0) padding = block_size;
return padding;
}


int XCrypt::Encrypt(const char* in_data, int insize, char* out_data, bool is_end)
{
if (!in_data || insize <= 0 || !out_data) return 0;
int write_size = 0;
DES_cblock in = { 0 }; // 输入数据
DES_cblock out = { 0 }; // 输出
const int block_size = sizeof(DES_cblock);
int data_size = 0;
int padding = block_size - insize % block_size;




for (int i = 0; i < insize; i += block_size)
{
if (insize - i < block_size)
{
data_size = insize - i;
}
else
{
data_size = block_size;
}


// 复制数据源
memcpy(in.bytes, in_data + write_size, data_size);


//填充 补充的数据大小
if (is_end && i + block_size >= insize) // 处理最后一块数据
{
if (padding == block_size)
{
DES_ecb_encrypt(&in, &out, &key_sch_, DES_ENCRYPT);
memcpy(out_data + write_size, &out.bytes, block_size);
write_size += block_size;
memset(in.bytes, padding, sizeof(in)); // 填充8
}
else
{
memset(in.bytes + insize % block_size, padding, padding);
}


}


// 加密数据
DES_ecb_encrypt(&in, &out, &key_sch_, DES_ENCRYPT);
memcpy(out_data + write_size, &out.bytes, block_size);


write_size += block_size;
}
return write_size;
}


int XCrypt::Decrypt(const char* in_data, int insize, char* out_data, bool is_end)
{
if (!in_data || insize <= 0 || !out_data) return 0;
int write_size = 0;
DES_cblock in = { 0 }; // 输入数据
DES_cblock out = { 0 }; // 输出
const int block_size = sizeof(DES_cblock);
int data_size = 0;
for (int i = 0; i < insize; i += block_size)
{
memcpy(in.bytes, in_data + write_size, block_size);


// 解密
DES_ecb_encrypt(&in, &out, &key_sch_, DES_DECRYPT);
data_size = block_size;
// 处理结尾填充
if (is_end && insize - i <= block_size)
{
data_size = block_size - out.bytes[7];
if (data_size == 0)
{
break;
}
else if (data_size < 0)
{
std::cerr << "Decrypt failed!padding size error!" << std::endl;
break;
}
}
memcpy(out_data + write_size, &out.bytes, data_size);
write_size += data_size;
}
return write_size;
}

XIOStream.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 线程基类,责任链模式、多线程数据传递、内存池注入和空间管理
**************************************************************************************************************/


#pragma once


#include <thread>
#include <mutex>
#include <list>
#include <memory_resource>


class XData;


class XIOStream
{
public:
// 线程启动
void Start();
// 等待线程退出
void Wait();
// 线程退出,需要用 Wait 等待
void Stop() { is_exit_ = true; }


void set_mem_pool(std::shared_ptr<std::pmr::memory_resource> mp) { memory_pool_ = mp; }


// 设置责任链下一个节点
void set_next(std::shared_ptr<XIOStream> next) { task_next_ = next; }


// 给对象传递数据,线程安全
void PushBack(std::shared_ptr<XData> data);


std::shared_ptr<XData> PopFront();
protected:
//线程入口
virtual void DoIt() {}


bool is_exit_ = false;
long long data_byte_ = 0; // 所有要处理数据的字节数
std::shared_ptr<std::pmr::memory_resource> memory_pool_; // 线程池
std::shared_ptr<XIOStream> task_next_; // 责任链代码


private:
std::thread io_thread_;
std::mutex io_mutex_;
std::list<std::shared_ptr<XData>> io_datas_;
};

XIOStream.cpp

#include "../include/XIOStream.h"
#include "../include/XData.h"


void XIOStream::Start()
{
io_thread_ = std::thread(&XIOStream::DoIt, this);
}


void XIOStream::Wait()
{
if (io_thread_.joinable())
io_thread_.join();
}


std::shared_ptr<XData> XIOStream::PopFront()
{
std::unique_lock<std::mutex> lock(io_mutex_);
if (io_datas_.empty())return nullptr;
auto re = io_datas_.front();
io_datas_.pop_front();
return re;
}


void XIOStream::PushBack(std::shared_ptr<XData> data)
{
std::unique_lock<std::mutex> lock(io_mutex_);
io_datas_.push_back(data);
}

XReadTask.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 文件读取类
**************************************************************************************************************/


#pragma once


#include "XIOStream.h"


#include <string>
#include <fstream>


class XReadTask :public XIOStream
{
public:
// 初始化读取线程,获取文件大小
bool Init(std::string filename);


private:
void DoIt();


std::ifstream read_stream_; //读取文件
};

XReadTask.cpp

#include "../include/XReadTask.h"
#include "../include/XData.h"
#include <iostream>


bool XReadTask::Init(std::string filename)
{
if (filename.empty())return false;
read_stream_.open(filename, std::ios::binary); //二进制打开
if (!read_stream_)
{
std::cerr << "open file " << filename << " failed!" << std::endl;
return false;
}
std::cout << filename << " open success!" << std::endl;
read_stream_.seekg(0, std::ios::end);
data_byte_ = read_stream_.tellg();
read_stream_.seekg(0, std::ios::beg);
std::cout << " file size " << data_byte_ << std::endl;


return true;
}


void XReadTask::DoIt()
{
std::cout << "begin thread XReadTask::Main" << std::endl;
while (!is_exit_)
{
if (read_stream_.eof())break;


// 创建内存池空间管理对象
auto data = XData::Make(this->memory_pool_);
int data_size = 1024;


// 申请空间
void* buf = data->New(data_size);


//读取文件
read_stream_.read((char*)buf, data_size);


if (read_stream_.gcount() <= 0)break;
data->set_size(read_stream_.gcount());
if (read_stream_.eof())
{
data->set_end(true);
}


if (task_next_)
{
task_next_->PushBack(data);
}
}
read_stream_.close();
std::cout << "end thread XReadTask::Main" << std::endl;
}

XCryptTask.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 加解密处理线程类
**************************************************************************************************************/


#pragma once
#include "XIOStream.h"


class XCrypt;


typedef enum {
Crypt_Null, // 空
Crypt_Encrypt, // 加密
Crypt_Decrypt // 解密
}CryptType;


class XCryptTask :public XIOStream
{
public:


//初始化加解密秘钥
void Init(std::string passwd);
void set_crypt_type(CryptType type) { crypt_type_ = type; }
private:
void DoIt();


std::shared_ptr<XCrypt> crpyt_;
CryptType crypt_type_ = Crypt_Null;
};

XCryptTask.cpp

#include "../include/XCryptTask.h"
#include "../include/XCrypt.h"
#include "../include/XData.h"
#include <iostream>
#include <thread>
#include <chrono>


void XCryptTask::Init(std::string passwd)
{
crpyt_ = std::make_shared<XCrypt>();
crpyt_->Init(passwd);
}


void XCryptTask::DoIt()
{
std::cout << "begin XCryptTask::Main()" << std::endl;
while (!is_exit_)
{
auto data = PopFront();
if (!data)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
auto out = XData::Make(memory_pool_);
int outsize = data->size() + crpyt_->GetPadding(data->size());
out->New(outsize);
int data_size = 0;
bool is_end = data->end();


switch (crypt_type_)
{
case Crypt_Null:
break;
case Crypt_Encrypt:
data_size = crpyt_->Encrypt((char*)data->data(), data->size(), (char*)out->data(), is_end);
break;
case Crypt_Decrypt:
data_size = crpyt_->Decrypt((char*)data->data(), data->size(), (char*)out->data(), is_end);
break;
default:
break;
}


out->set_size(data_size);


std::cout << "{" << out->size() << "}" << std::flush;
out->set_end(data->end());


if (task_next_)
{
task_next_->PushBack(out);
}
if (data->end())
{
break;
}
}
std::cout << "end XCryptTask::Main()" << std::endl;
}

XWriteTask.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 文件写入类
**************************************************************************************************************/


#pragma once
#include "XIOStream.h"
#include <fstream>


class XWriteTask :public XIOStream
{
public:
bool Init(std::string filename);
private:
void DoIt();




std::ofstream write_stream_;
};


XWriteTask.cpp

#include "../include/XWriteTask.h"
#include "../include/XData.h"
#include <iostream>


bool XWriteTask::Init(std::string filename)
{
write_stream_.open(filename, std::ios::binary);
if (!write_stream_)
{
std::cerr << "open file " << filename.c_str() << " failed!" << std::endl;
return false;
}
std::cout << filename.c_str() << " open success!" << std::endl;
return true;
}


void XWriteTask::DoIt()
{
while (!is_exit_)
{
auto data = PopFront();
if (!data)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
write_stream_.write((char*)data->data(), data->size());
if (data->end())
break;
}


write_stream_.close();
}

XFileCrypt.h

/**************************************************************************************************************
* vic.MINg 2021-09-13
* 处理文件加解密任务,对整体流程的封装
**************************************************************************************************************/




#pragma once
#include <string>
#include <memory>
#include "XCryptTask.h"


class XReadTask;
class XWriteTask;


class XFileCrypt
{
public:
bool Start(std::string infile, std::string outfile, std::string passwd, CryptType type = Crypt_Encrypt);
void Wait();


private:
std::shared_ptr<XReadTask> read_task_;
std::shared_ptr<XCryptTask> crypt_task_;
std::shared_ptr<XWriteTask> write_task_;
};

XFileCrypt.cpp

#include "../include/XFileCrypt.h"
#include "../include/XReadTask.h"
#include "../include/XWriteTask.h"


#include <iostream>


bool XFileCrypt::Start(std::string infile, std::string outfile, std::string passwd, CryptType type)
{
//创建一个内存池
std::shared_ptr<std::pmr::memory_resource> mp(new std::pmr::synchronized_pool_resource());


read_task_ = std::make_shared<XReadTask>();
read_task_->Init(infile);
read_task_->set_mem_pool(mp);


crypt_task_ = std::make_shared<XCryptTask>();
crypt_task_->set_mem_pool(mp);
crypt_task_->set_crypt_type(type);
crypt_task_->Init(passwd);
read_task_->set_next(crypt_task_);


write_task_ = std::make_shared<XWriteTask>();
write_task_->set_mem_pool(mp);
write_task_->Init(outfile);


crypt_task_->set_next(write_task_);


read_task_->Start();
crypt_task_->Start();
write_task_->Start();


return true;
}
void XFileCrypt::Wait()
{
if (read_task_)
read_task_->Wait();
if (crypt_task_)
crypt_task_->Wait();
if (write_task_)
write_task_->Wait();
}

测试

main.cpp

#include "../include/XFileCrypt.h"
#include <string>
#include <memory>


#include "../include/DirectoryManager.h"


int main(int _Argc, char* argv[])
{
std::string passwd = "vic.MINg";
{
std::string strText_source, strText_crypt, strText_target;
#ifdef _WIN32
strText_source = DirectoryManager::GetExeDirectory() + "test_source.txt";
strText_crypt = DirectoryManager::GetExeDirectory() + "test_crypt.txt";
strText_target = DirectoryManager::GetExeDirectory() + "test_target.txt";
#else
strText_source = "test_source.txt";
strText_crypt = "test_crypt.txt";
strText_target = "test_target.txt";
#endif




auto xfc = std::make_shared<XFileCrypt>();
xfc->Start(strText_source, strText_crypt, passwd, CryptType::Crypt_Encrypt);
xfc->Wait();


auto xfd = std::make_shared<XFileCrypt>();
xfd->Start(strText_crypt, strText_target, passwd, CryptType::Crypt_Decrypt);
xfd->Wait();


}


system("pause");


return 0;
}


文章转载自林元皓,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论