前言 還記得你第一次遇到「線程安全」這個詞的時候嗎? 我第一次遇到線程安全這個詞是在學習多線程併發操作的時候,看到人家文章里出現這個詞,還有說各種線程安全的類,但是一開始並不理解線程安全是什麼意思,也沒去深究線程怎樣是安全的?怎樣是不安全的?只是腦子裡接收了這麼一個詞。 線程安全是多線程編程時的計算 ...
將Nginx中的記憶體池實現移植到c++,通過面向對象的方式實現
頭文件:
//
// Created by 26685 on 2022-05-29 19:57.
// Description:NginxMemoryPool.h
//
#ifndef MEMORYPOOL_NGINXMEMORYPOOL_H
#define MEMORYPOOL_NGINXMEMORYPOOL_H
#include<cstdlib>
#include<cstdio>
#include<memory.h>
using u_char = unsigned char;
using ngx_uint_t = unsigned int;
using ngx_pool_cleanup_pt = void (*)(void *data);//函數指針ngx_pool_cleanup_pt
struct ngx_pool_s;
//清除節點
struct ngx_pool_cleanup_s {
ngx_pool_cleanup_pt handler;//回調函數
void *data;//上面函數中使用的數據
ngx_pool_cleanup_s *next;
};
//指向下一個大尺寸pool的節點
struct ngx_pool_large_s {
ngx_pool_large_s *next;//next指針,指向下一個節點
void *alloc;//堆記憶體地址(大塊記憶體地址)
};
//指向下一個小尺寸pool頭結點的結構
struct ngx_pool_data_s {
u_char *last;
u_char *end;
ngx_pool_s *next;
ngx_uint_t failed;
};
//記憶體池的頭文件
struct ngx_pool_s {
ngx_pool_data_s d;
size_t max;
ngx_pool_s *current;
ngx_pool_large_s *large;
ngx_pool_cleanup_s *cleanup;
};
//將p調整為a的倍數
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
//將d調整為a的倍數
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
//將記憶體塊設置為0
#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
#define NGX_OK 0
#define NGX_ERROR -1
#define NGX_AGAIN -2
#define NGX_BUSY -3
#define NGX_DONE -4
#define NGX_DECLINED -5
#define NGX_ABORT -6
const int NGX_ALIGNMENT = sizeof(unsigned long);//對齊長度
const int ngx_pagesize = 4096;//最大頁面大小4k
const int NGX_MAX_ALLOC_FROM_POOL = ngx_pagesize - 1;//最大小記憶體池
const int NGX_DEFAULT_POOL_SIZE = 16 * 1024;//
const int NGX_POOL_ALIGNMENT = 16;
const int NGX_MIN_POOL_SIZE = ngx_align((sizeof(ngx_pool_s) + 2 * sizeof(ngx_pool_large_s)), \
NGX_POOL_ALIGNMENT);
class NginxMemoryPool {
public:
explicit NginxMemoryPool(size_t size = 512);
~NginxMemoryPool() {
printf("destroy pool! \n");
ngx_destroy_pool();
}
void *ngx_create_pool(size_t size);
void ngx_destroy_pool();
void ngx_reset_pool();
//考慮記憶體對齊,從記憶體池申請size大小的記憶體
void *ngx_palloc(size_t size);
//不考慮記憶體對齊
void *ngx_pnalloc(size_t size);
void *ngx_pcalloc(size_t size);
//添加回調清理操作函數
ngx_pool_cleanup_s *ngx_pool_cleanup_add(size_t size);
//釋放大塊記憶體
int ngx_pfree(void *p);
private:
ngx_pool_s *pool{};
void *ngx_palloc_small(size_t size, ngx_uint_t align);
void *ngx_palloc_block(size_t size);
void *ngx_palloc_large(size_t size);
};
#endif //MEMORYPOOL_NGINXMEMORYPOOL_H
.cpp實現
//
// Created by 26685 on 2022-05-29 19:57.
// Description:NginxMemoryPool.cpp
//
#include "include/NginxMemoryPool.h"
ngx_pool_cleanup_s *NginxMemoryPool::ngx_pool_cleanup_add(size_t size) {
ngx_pool_cleanup_s *c;
c = (ngx_pool_cleanup_s *) ngx_palloc(sizeof(ngx_pool_cleanup_s));
if (c == nullptr) {
return nullptr;
}
if (size) {
c->data = ngx_palloc(size);
if (c->data == nullptr) {
return nullptr;
}
} else {
c->data = nullptr;
}
c->handler = nullptr;
c->next = pool->cleanup;
pool->cleanup = c;
return c;
}
void *NginxMemoryPool::ngx_create_pool(size_t size) {
ngx_pool_s *p;
p = (ngx_pool_s *) malloc(size);//按照16位元組對齊
if (p == nullptr) {
return nullptr;
}
p->d.last = (u_char *) p + sizeof(ngx_pool_s);
p->d.end = (u_char *) p + size;
p->d.next = nullptr;
p->d.failed = 0;
size = size - sizeof(ngx_pool_s);
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
p->current = p;
p->large = nullptr;
p->cleanup = nullptr;
pool = p;
return p;
}
void NginxMemoryPool::ngx_destroy_pool() {
ngx_pool_s *p, *n;
ngx_pool_large_s *l;
ngx_pool_cleanup_s *c;
//現根據記憶體池中的cleanup保存的信息把大塊記憶體中指向的外部資源釋放掉
for (c = pool->cleanup; c; c = c->next) {
if (c->handler) {
c->handler(c->data);
}
}
//清理掉外部資源後將大塊記憶體釋放掉
for (l = pool->large; l; l = l->next) {//遍歷每一個large記憶體
if (l->alloc) {
free(l->alloc);
}
}
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
free(p);
if (n == nullptr) {
break;
}
}
}
void NginxMemoryPool::ngx_reset_pool() {
ngx_pool_s *p;
ngx_pool_large_s *l;
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
free(l->alloc);
}
}
//第一塊記憶體的頭是sizeof(ngx_pool_s)
p->d.last = (u_char *) p + sizeof(ngx_pool_s);
p->d.failed = 0;
//後面記憶體塊的頭的大小是sizeof(ngx_pool_data_s)
for (p = pool->d.next; p; p = p->d.next) {
p->d.last = (u_char *) p + sizeof(ngx_pool_data_s);
p->d.failed = 0;
}
pool->current = pool;
pool->large = nullptr;
}
void *NginxMemoryPool::ngx_palloc(size_t size) {
if (size <= pool->max) {
return ngx_palloc_small(size, 1);
}
return ngx_palloc_large(size);
}
void *NginxMemoryPool::ngx_pnalloc(size_t size) {
if (size <= pool->max) {
return ngx_palloc_small(size, 0);
}
return ngx_palloc_large(size);
}
void *NginxMemoryPool::ngx_pcalloc(size_t size) {
void *p;
p = ngx_palloc(size);
if (p) {
ngx_memzero(p, size);
}
return p;
}
int NginxMemoryPool::ngx_pfree(void *p) {
ngx_pool_large_s *l;
for (l = pool->large; l; l = l->next) {
if (p == l->alloc) {
free(l->alloc);
l->alloc = nullptr;
return NGX_OK;
}
}
return NGX_DECLINED;
}
void *NginxMemoryPool::ngx_palloc_small(size_t size, ngx_uint_t align) {
u_char *m;
ngx_pool_s *p;
p = pool->current;
do {
m = p->d.last;
if (align) {
m = ngx_align_ptr(m, NGX_ALIGNMENT);
}
if ((size_t) (p->d.end - m) >= size) {
p->d.last = m + size;
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(size);
}
void *NginxMemoryPool::ngx_palloc_block(size_t size) {
u_char *m;
size_t psize;
ngx_pool_s *p, *newMem;
psize = (size_t) (pool->d.end - (u_char *) pool);
m = (u_char *) malloc(psize);
if (m == nullptr) {
return nullptr;
}
newMem = (ngx_pool_s *) m;
newMem->d.end = m + psize;
newMem->d.next = nullptr;
newMem->d.failed = 0;
m += sizeof(ngx_pool_data_s);
m = ngx_align_ptr(m, NGX_ALIGNMENT);
newMem->d.last = m + size;
for (p = pool->current; p->d.next; p = p->d.next) {
if (p->d.failed++ > 4) {
pool->current = p->d.next;
}
}
p->d.next = newMem;
return m;
}
void *NginxMemoryPool::ngx_palloc_large(size_t size) {
void *p;
ngx_uint_t n;
ngx_pool_large_s *large;
p = malloc(size);
if (p == nullptr) {
return nullptr;
}
n = 0;
for (large = pool->large; large; large = large->next) {
if (large->alloc == nullptr) {
large->alloc = p;
return p;
}
if (n++ > 3) {
break;
}
}
large = (ngx_pool_large_s *) ngx_palloc_small(sizeof(ngx_pool_large_s), 1);//在小塊池中建立large記憶體塊
if (large == nullptr) {
free(p);
return nullptr;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
NginxMemoryPool::NginxMemoryPool(size_t size) {
printf("%d\n", size);
ngx_create_pool(size);
}
測試代碼:
#include <iostream>
#include <cstring>
#include "include/NginxMemoryPool.h"
typedef struct Data stData;
struct Data {
char *ptr;
FILE *pfile;
};
void func1(void *p1) {
char *p = (char *) p1;
printf("free ptr mem!\n");
free(p);
}
void func2(void *pf1) {
FILE *pf = (FILE *) pf1;
printf("close file!\n");
fclose(pf);
}
int main() {
NginxMemoryPool pool;
// 512 - sizeof(ngx_pool_t) - 4095 => max
//pool.ngx_create_pool(512);
void *p1 = pool.ngx_palloc(128); // 從小塊記憶體池分配的
if (p1 == nullptr) {
printf("ngx_palloc 128 bytes fail...");
return -1;
}
stData *p2 = (stData *) pool.ngx_palloc(512); // 從大塊記憶體池分配的
if (p2 == nullptr) {
printf("ngx_palloc 512 bytes fail...");
return -1;
}
p2->ptr = (char *) malloc(12);
strcpy(p2->ptr, "hello world\n");
p2->pfile = fopen("data.txt", "w");
ngx_pool_cleanup_s *c1 = pool.ngx_pool_cleanup_add(sizeof(char *));
c1->handler = func1;
c1->data = p2->ptr;
ngx_pool_cleanup_s *c2 = pool.ngx_pool_cleanup_add(sizeof(FILE *));
c2->handler = func2;
c2->data = p2->pfile;
//pool.ngx_destroy_pool(); // 1.調用所有的預置的清理函數 2.釋放大塊記憶體 3.釋放小塊記憶體池所有記憶體
return 1;
}