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

C++单例模式代码实现与分析

目录

1 代码

2 代码剖析

2.1 构造函数私有化

2.2 只能执行一次的代码

2.3 静态成员变量

2.4 智能指针


1 代码

下面的代码是https://github.com/Cambricon/CNStream 中的,

/*************************************************************************
 * Copyright (C) [2022] by Cambricon, Inc. All rights reserved
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a Copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *************************************************************************/

#include "buf_surface.h"

#include <algorithm>
#include <cstring>  // for memset
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <thread>

#include "glog/logging.h"

#include "buf_surface_impl.h"
#include "nvis/infer_server.h"
#include "common/utils.hpp"

namespace infer_server {

    class BufSurfaceService {
    public:
        static BufSurfaceService &Instance() {
            static std::once_flag s_flag;
            std::call_once(s_flag, [&] { instance_.reset(new BufSurfaceService); });
            return *instance_;
        }
        ~BufSurfaceService() = default;
        int BufPoolCreate(void **pool, BufSurfaceCreateParams *params, uint32_t block_num) {
            if (pool && params && block_num) {
                MemPool *mempool = new MemPool();
                if (!mempool) {
                    LOG(ERROR) << "[InferServer] [BufSurfaceService] BufPoolCreate(): new memory pool failed";
                    return -1;
                }
                *pool = reinterpret_cast<void *>(mempool);
                if (mempool->Create(params, block_num) == 0) {
                    return 0;
                }
                delete mempool;
                LOG(ERROR) << "[InferServer] [BufSurfaceService] BufPoolCreate(): Create memory pool failed";
                return -1;
            }
            return -1;
        }
        int BufPoolDestroy(void *pool) {
            if (pool) {
                MemPool *mempool = reinterpret_cast<MemPool *>(pool);
                if (mempool) {
                    int ret = mempool->Destroy();
                    if (ret != 0) {
                        VLOG(3) << "[InferServer] [BufSurfaceService] BufPoolDestroy(): Destroy memory pool failed, ret = " << ret;
                        return ret;
                    }
                    delete mempool;
                }
                return 0;
            }
            LOG(ERROR) << "[InferServer] [BufSurfaceService] BufPoolDestroy(): Pool is not existed";
            return -1;
        }
        int CreateFromPool(BufSurface **surf, void *pool) {
            if (surf && pool) {
                BufSurface surface;
                MemPool *mempool = reinterpret_cast<MemPool *>(pool);
                if (mempool->Alloc(&surface) < 0) {
                    VLOG(4) << "[InferServer] [BufSurfaceService] CreateFromPool(): Create BufSurface from pool failed";
                    return -1;
                }
                *surf = AllocSurface();
                if (!(*surf)) {
                    mempool->Free(&surface);
                    LOG(WARNING) << "[InferServer] [BufSurfaceService] CreateFromPool(): Alloc BufSurface failed";
                    return -1;
                }
                *(*surf) = surface;
                return 0;
            }
            LOG(ERROR) << "[InferServer] [BufSurfaceService] CreateFromPool(): surf or pool is nullptr";
            return -1;
        }
        int Create(BufSurface **surf, BufSurfaceCreateParams *params) {
            if (surf && params) {
                if (CheckParams(params) < 0) {
                    LOG(ERROR) << "[InferServer] [BufSurfaceService] Create(): Parameters are invalid";
                    return -1;
                }
                BufSurface surface;
                if (CreateSurface(params, &surface) < 0) {
                    LOG(ERROR) << "[InferServer] [BufSurfaceService] Create(): Create BufSurface failed";
                    return -1;
                }
                *surf = AllocSurface();
                if (!(*surf)) {
                    DestroySurface(&surface);
                    LOG(ERROR) << "[InferServer] [BufSurfaceService] Create(): Alloc BufSurface failed";
                    return -1;
                }
                *(*surf) = surface;
                return 0;
            }
            LOG(ERROR) << "[InferServer] [BufSurfaceService] Create(): surf or params is nullptr";
            return -1;
        }

        int Destroy(BufSurface *surf) {
            if (!surf) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Destroy(): surf is nullptr";
                return -1;
            }

            if (surf->opaque) {
                MemPool *mempool = reinterpret_cast<MemPool *>(surf->opaque);
                int ret = mempool->Free(surf);
                FreeSurface(surf);
                if (ret) {
                    LOG(ERROR) << "[InferServer] [BufSurfaceService] Destroy(): Free BufSurface back to memory pool failed";
                }
                return ret;
            }

            // created by BufSurfaceCreate()
            int ret = DestroySurface(surf);
            FreeSurface(surf);
            if (ret) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Destroy(): Destroy BufSurface failed";
            }
            return ret;
        }

        int Memset(BufSurface *surf, int index, uint8_t value) {
            if (!surf) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Memset(): BufSurface is nullptr";
                return -1;
            }
            if (index < -1 || index >= static_cast<int>(surf->batch_size)) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Memset(): batch index is invalid";
                return -1;
            }

            for (uint32_t i = 0; i < surf->batch_size; i++) {
                if (index >= 0 && i != static_cast<uint32_t>(index)) continue;
                CUDA_SAFECALL(cudaMemset(surf->surface_list[i].data_ptr, value, surf->surface_list[i].data_size), "[InferServer] [BufSurfaceService] Memset(): failed", -1);
            }
            return 0;
        }

        int Copy(BufSurface *src_surf, BufSurface *dst_surf) {
            if (!src_surf || !dst_surf) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Copy(): src or dst BufSurface is nullptr";
                return -1;
            }
            // check parameters, must be the same size
            if (src_surf->batch_size != dst_surf->batch_size) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Copy(): src and dst BufSurface has different batch size";
                return -1;
            }

            dst_surf->pts = src_surf->pts;
            bool src_host = (src_surf->mem_type == BUF_MEMORY_HOST);

            bool dst_host = (dst_surf->mem_type == BUF_MEMORY_HOST);

            if ((!dst_host && !src_host) && (src_surf->device_id != dst_surf->device_id)) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] Copy(): src and dst BufSurface is on different device";
                return -1;
            }

            for (size_t i = 0; i < src_surf->batch_size; ++i) {
                CUDA_SAFECALL(MemcpyHD(dst_surf->surface_list[i].data_ptr, dst_surf->mem_type
                    , src_surf->surface_list[i].data_ptr, src_surf->mem_type, dst_surf->surface_list[i].data_size),
                    "[InferServer] [BufSurfaceService] Copy(): failed", -1);
            }

            return 0;
        }

    private:
        BufSurfaceService(const BufSurfaceService &) = delete;
        BufSurfaceService(BufSurfaceService &&) = delete;
        BufSurfaceService &operator=(const BufSurfaceService &) = delete;
        BufSurfaceService &operator=(BufSurfaceService &&) = delete;
        BufSurfaceService() = default;

    private:
        std::mutex mutex_;
        bool initialized_ = false;
        std::queue<BufSurface *> surfpool_;
        BufSurface *start_ = nullptr, *end_ = nullptr;
        static const int k_surfs_num_ = 256 * 1024;

    private:
        void CreateSurfsPool() {
            if (initialized_) return;
            start_ = reinterpret_cast<BufSurface *>(malloc(sizeof(BufSurface) * k_surfs_num_));
            if (!start_) {
                LOG(ERROR) << "[InferServer] [BufSurfaceService] CreateSurfsPool(): Create BufSurface pointers failed";
                return;
            }
            end_ = &start_[k_surfs_num_ - 1];
            for (int i = 0; i < k_surfs_num_; i++) surfpool_.push(&start_[i]);
            initialized_ = true;
        }

        BufSurface *AllocSurface() {
            std::unique_lock<std::mutex> lk(mutex_);
            if (!initialized_) CreateSurfsPool();
            if (!surfpool_.empty()) {
                BufSurface *res = surfpool_.front();
                surfpool_.pop();
                return res;
            }
            return reinterpret_cast<BufSurface *>(malloc(sizeof(BufSurface)));
        }

        void FreeSurface(BufSurface *surf) {
            std::unique_lock<std::mutex> lk(mutex_);
            if (surf >= start_ && surf <= end_) {
                surfpool_.push(surf);
                return;
            }
            ::free(surf);
        }

    private:
        static std::unique_ptr<BufSurfaceService> instance_;
    };

    std::unique_ptr<BufSurfaceService> BufSurfaceService::instance_;

}  // namespace 

extern "C" {
    int BufPoolCreate(void **pool, BufSurfaceCreateParams *params, uint32_t block_num) {
        return infer_server::BufSurfaceService::Instance().BufPoolCreate(pool, params, block_num);
    }

    int BufPoolDestroy(void *pool) { return infer_server::BufSurfaceService::Instance().BufPoolDestroy(pool); }

    int BufSurfaceCreateFromPool(BufSurface **surf, void *pool) {
        return infer_server::BufSurfaceService::Instance().CreateFromPool(surf, pool);
    }

    int BufSurfaceCreate(BufSurface **surf, BufSurfaceCreateParams *params) {
        return infer_server::BufSurfaceService::Instance().Create(surf, params);
    }

    int BufSurfaceDestroy(BufSurface *surf) { return infer_server::BufSurfaceService::Instance().Destroy(surf); }

    int BufSurfaceMemSet(BufSurface *surf, int index, uint8_t value) {
        return infer_server::BufSurfaceService::Instance().Memset(surf, index, value);
    }

    int BufSurfaceCopy(BufSurface *src_surf, BufSurface *dst_surf) {
        return infer_server::BufSurfaceService::Instance().Copy(src_surf, dst_surf);
    }

};  // extern "C"

2 代码剖析

简单看一下代码,看一下他怎么实现的单例模式

2.1 构造函数私有化

    private:
        BufSurfaceService(const BufSurfaceService &) = delete;
        BufSurfaceService(BufSurfaceService &&) = delete;
        BufSurfaceService &operator=(const BufSurfaceService &) = delete;
        BufSurfaceService &operator=(BufSurfaceService &&) = delete;
        BufSurfaceService() = default;

把所有的构造函数都声明成私有的,这样让用户只能通过下面的函数去实例化

        static BufSurfaceService &Instance() {
            static std::once_flag s_flag;
            std::call_once(s_flag, [&] { instance_.reset(new BufSurfaceService); });
            return *instance_;
        }

2.2 只能执行一次的代码

        static BufSurfaceService &Instance() {
            static std::once_flag s_flag;
            std::call_once(s_flag, [&] { instance_.reset(new BufSurfaceService); });
            return *instance_;
        }

这地方用了call_once保证后面的lambda表达式只会被执行一次。

2.3 静态成员变量

    private:
        static std::unique_ptr<BufSurfaceService> instance_;
    };

    std::unique_ptr<BufSurfaceService> BufSurfaceService::instance_;

}  // namespace 

类里面声明了一个静态成员变量,并且在类外面对他进行了定义,但是这里只是给这个智能指针本身分配了内存,并没给他赋值,在调用Instance()函数的时候再给他赋值。

2.4 智能指针

    private:
        static std::unique_ptr<BufSurfaceService> instance_;
    };

    std::unique_ptr<BufSurfaceService> BufSurfaceService::instance_;

}  // namespace 

这里的静态成员变量用的智能指针,防止内存泄漏。

参考文献:

C++_单例模式_c++单例模式-CSDN博客

C++ 设计模式——单例模式_c++ 单例模式-CSDN博客

GitHub - Cambricon/CNStream: CNStream is a streaming framework for building Cambricon machine learning pipelines http://forum.cambricon.com https://gitee.com/SolutionSDK/CNStream


http://www.kler.cn/a/316313.html

相关文章:

  • 【STM32】基于SPI协议读写SD,详解!
  • 想租用显卡训练自己的网络?AutoDL保姆级使用教程(PyCharm版)
  • 第8章 利用CSS制作导航菜单
  • Iceberg 写入和更新模式,COW,MOR(Copy-on-Write,Merge-on-Read)
  • springboot参数校验
  • Lodash的常用方法整理
  • Spring Boot实用小技巧5 - 第527篇
  • Leetcode面试经典150题-198.打家劫舍
  • 【Git使用】删除Github仓库中的指定文件/文件夹
  • Linux通过yum安装Docker
  • 5G 扬帆新质跃,技术蝶变开新篇-第七届“绽放杯”5G应用征集大赛 5G应用融合技术专题赛圆满收官
  • mysql性能优化-索引优化
  • 一天认识一个硬件之内存条
  • 1688国内店铺装修新版后台 放大效果代码生成1688店铺怎么装修1688平台
  • 通过解预测和机器学习促进蚁群优化
  • 用户态缓存:环形缓冲区(Ring Buffer)
  • Python 中的 Kombu 类库
  • 前端vue压缩静态图片,压缩gif动态图片
  • Anaconda配置pytorch的基本操作
  • Error when custom data is added to Azure OpenAI Service Deployment
  • Python办公自动化教程(001):PDF内容提取
  • Junit与Spring Test简单使用
  • AI量化交易机器人开发
  • docker挂载宿主机文件run命令启动报错
  • 如何选购笔记本电脑?要看哪些参数?
  • C++重生之我是001