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

目录

[1 代码](#1 代码)

[2 代码剖析](#2 代码剖析)

[2.1 构造函数私有化](#2.1 构造函数私有化)

[2.2 只能执行一次的代码](#2.2 只能执行一次的代码)

[2.3 静态成员变量](#2.3 静态成员变量)

[2.4 智能指针](#2.4 智能指针)


1 代码

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

cpp 复制代码
/*************************************************************************
 * 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 构造函数私有化

cpp 复制代码
    private:
        BufSurfaceService(const BufSurfaceService &) = delete;
        BufSurfaceService(BufSurfaceService &&) = delete;
        BufSurfaceService &operator=(const BufSurfaceService &) = delete;
        BufSurfaceService &operator=(BufSurfaceService &&) = delete;
        BufSurfaceService() = default;

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

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

2.2 只能执行一次的代码

cpp 复制代码
        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 静态成员变量

cpp 复制代码
    private:
        static std::unique_ptr<BufSurfaceService> instance_;
    };

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

}  // namespace 

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

2.4 智能指针

cpp 复制代码
    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

相关推荐
蜀黍@猿11 分钟前
C/C++基础错题归纳
c++
雨中rain26 分钟前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
ALISHENGYA1 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
arong_xu2 小时前
现代C++锁介绍
c++·多线程·mutex
汤姆和杰瑞在瑞士吃糯米粑粑2 小时前
【C++学习篇】AVL树
开发语言·c++·学习
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
奶香臭豆腐3 小时前
C++ —— 模板类具体化
开发语言·c++·学习
不想当程序猿_3 小时前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
cdut_suye3 小时前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python