Skip to content

Utils_ObjectsPool

SweerItTer edited this page Feb 1, 2026 · 3 revisions

ObjectsPool API 文档

概述

ObjectsPool 是 utilsCore Utils 模块的核心类,提供对象池功能,用于管理可复用的对象实例,减少对象创建和销毁的开销。

职责

  • 预创建对象池
  • 提供对象获取(acquire)和归还(release)
  • 支持阻塞和超时获取
  • 线程安全的对象池管理

适用场景

  • 频繁创建和销毁对象
  • 对象初始化开销较大的场景
  • 资源有限的环境
  • YOLO 模型推理(rknnPool 使用)

性能优势

  • 对象复用: 避免重复创建对象
  • 减少分配: 降低内存分配次数
  • 线程安全: 内置互斥锁保护

依赖关系

  • 依赖: C++ STL
  • 被依赖: rknnPool, YOLO 处理器等模块

类分析

ObjectsPool 类

职责与用途

ObjectsPool 是对象池的模板类,管理类型为 T 的对象集合:

  • 构造时预创建对象
  • acquire() 获取空闲对象,无则阻塞等待
  • release() 归还对象到池
  • 支持超时获取

设计模式

  • 对象池模式: 复用对象,减少创建/销毁开销
  • 生产者-消费者: 使用条件变量同步
  • 模板模式: 支持任意可复制的对象类型

公共 API 方法

ObjectPool() - 构造函数

ObjectPool(size_t poolSize, CreatorFunc creator)

参数说明:

  • poolSize (输入): 池的大小(对象数量)
  • creator (输入): 对象创建函数 std::function<T()>

返回值: 无

所有权归属:

  • ObjectPool 拥有池中所有对象的所有权

注意事项:

  1. 构造时立即创建 poolSize 个对象
  2. creator 函数必须返回有效的对象
  3. 对象类型 T 必须支持移动语义

使用例程:

// 创建对象池,预创建 10 个对象
ObjectPool<MyClass> pool(10, []() {
    return MyClass();  // 对象创建函数
});

// 使用 Lambda 创建带参数的对象
ObjectPool<MyClass> pool(10, []() {
    return MyClass(42, "test");
});

// 使用工厂函数
MyClass createMyClass() {
    return MyClass(100);
}
ObjectPool<MyClass> pool(5, createMyClass);

acquire() - 获取对象

T acquire()

参数说明: 无

返回值:

  • 成功: 返回对象(移动语义)
  • 失败: 阻塞直到有对象可用

所有权归属:

  • 返回对象的所有权转移给调用者
  • 调用者负责归还对象到池

注意事项:

  1. 如果池为空,阻塞等待直到有对象可用
  2. 返回的对象使用移动语义
  3. 必须在使用后调用 release() 归还对象

使用例程:

ObjectPool<MyClass> pool(10, []() { return MyClass(); });

// 获取对象(阻塞等待)
MyClass obj = pool.acquire();

// 使用对象
obj.doSomething();

// 归还对象
pool.release(std::move(obj));

tryAcquire() - 尝试获取对象

bool tryAcquire(T& obj, std::chrono::milliseconds timeout)

参数说明:

  • obj (输出): 输出参数,接收获取的对象
  • timeout (输入): 超时时间(毫秒)

返回值:

  • 成功: 返回 true,obj 包含对象
  • 失败/超时: 返回 false,obj 保持不变

所有权归属:

  • 成功时对象的所有权转移给调用者

注意事项:

  1. 非阻塞获取,支持超时
  2. 超时返回 false,避免死锁
  3. obj 使用引用传递,通过移动语义赋值

使用例程:

ObjectPool<MyClass> pool(10, []() { return MyClass(); });

MyClass obj;
if (pool.tryAcquire(obj, std::chrono::milliseconds(1000))) {
    // 成功获取对象
    obj.doSomething();
    pool.release(std::move(obj));
} else {
    // 超时,没有可用对象
    printf("Timeout: No available object\n");
}

release() - 归还对象

void release(T obj)

参数说明:

  • obj (输入): 要归还的对象(移动语义)

返回值: 无

所有权归属:

  • 对象的所有权转移回对象池

注意事项:

  1. 使用移动语义归还对象
  2. 归还后会唤醒一个等待的 acquire() 调用
  3. 如果池已满(理论上不会,因为池大小固定),对象会丢失

使用例程:

MyClass obj = pool.acquire();
// 使用对象...
pool.release(std::move(obj));  // 归还对象

freeCount() - 获取空闲对象数量

size_t freeCount() const

参数说明: 无

返回值: 池中当前空闲对象数量

所有权归属:

  • 只读访问,不转移所有权

注意事项:

  1. 返回值可能因多线程并发访问而快速变化
  2. 只能作为参考,不应依赖其做关键判断

使用例程:

printf("Free objects: %zu\n", pool.freeCount());

内部实现

数据结构

template<typename T>
class ObjectPool {
private:
    CreatorFunc creator_;                // 对象创建函数
    mutable std::mutex mutex_;            // 互斥锁
    std::condition_variable cond_;        // 条件变量
    std::queue<T> free_;                 // 空闲对象队列
};

工作流程

获取对象流程

1. 调用 acquire()
   ↓
2. 获取互斥锁
   ↓
3. 等待条件变量(队列非空)
   ↓
4. 从队列前端取出对象
   ↓
5. 释放互斥锁
   ↓
6. 返回对象

归还对象流程

1. 调用 release(obj)
   ↓
2. 获取互斥锁
   ↓
3. 对象推入队列尾部
   ↓
4. 通知一个等待线程
   ↓
5. 释放互斥锁
   ↓
6. 返回

所有权规则总结

资源 创建者 拥有者 释放方式 线程保护
池中对象 creator 函数 ObjectPool ObjectPool 析构时 mutex_
acquire() 后的对象 ObjectPool 调用者 必须调用 release() -
release() 后的对象 调用者 ObjectPool 重新入队 mutex_

所有权传递规则

分配流:
creator() → ObjectPool 构造 → std::queue<T> → acquire() → 调用者持有

归还流:
调用者 → release(T&&) → std::queue<T> → 等待中的 acquire() → 新调用者持有

线程安全说明

同步机制

  • 互斥锁: std::mutex mutex_ 保护队列操作
  • 条件变量: std::condition_variable cond_ 实现等待/通知
  • 原子操作: 无

线程安全保证

  • acquire() 可以多线程并发调用
  • tryAcquire() 可以多线程并发调用
  • release() 可以多线程并发调用
  • freeCount() 可以多线程并发调用

注意事项

  • 对象类型 T 本身不是线程安全的,需要外部同步
  • 多个线程获取同一个对象时,需要额外的同步机制

典型使用场景

场景 1: 基本使用

// 定义对象类型
class Worker {
public:
    Worker(int id) : id_(id) {
        printf("Worker %d created\n", id_);
    }
    
    ~Worker() {
        printf("Worker %d destroyed\n", id_);
    }
    
    void work() {
        printf("Worker %d working\n", id_);
    }
    
private:
    int id_;
};

// 创建对象池
ObjectPool<Worker> pool(5, []() {
    static int id = 0;
    return Worker(++id);
});

// 获取和使用对象
Worker w = pool.acquire();
w.work();
pool.release(std::move(w));

场景 2: YOLO 模型推理池

// YOLO 模型类型
class YoloModel {
public:
    YoloModel(const std::string& path) {
        // 加载模型
        model_ = load_model(path);
    }
    
    ~YoloModel() {
        // 释放模型
        release_model(model_);
    }
    
    object_detect_result_list infer(DmaBufferPtr buffer) {
        // 执行推理
        return run_inference(model_, buffer);
    }
    
private:
    ModelHandle model_;
};

// 创建模型池
ObjectPool<YoloModel> modelPool(5, [path]() {
    return YoloModel(path);
});

// 使用模型推理
YoloModel model = modelPool.acquire();
auto result = model.infer(buffer);
modelPool.release(std::move(model));

场景 3: 多线程环境

ObjectPool<Worker> pool(10, []() { return Worker(); });

std::vector<std::thread> threads;
for (int i = 0; i < 8; ++i) {
    threads.emplace_back([&pool]() {
        for (int j = 0; j < 100; ++j) {
            Worker w = pool.acquire();
            w.work();
            pool.release(std::move(w));
        }
    });
}

for (auto& t : threads) {
    t.join();
}

场景 4: 超时获取

ObjectPool<Worker> pool(5, []() { return Worker(); });

Worker w;
if (pool.tryAcquire(w, std::chrono::milliseconds(100))) {
    // 成功获取
    w.work();
    pool.release(std::move(w));
} else {
    // 超时
    printf("Failed to acquire worker (timeout)\n");
}

场景 5: 自定义创建函数

class DatabaseConnection {
public:
    DatabaseConnection(const std::string& host, int port)
        : host_(host), port_(port) {
        // 建立连接
        connect(host, port);
    }
    
    ~DatabaseConnection() {
        // 关闭连接
        disconnect();
    }
    
    void query(const std::string& sql) { /* ... */ }
    
private:
    std::string host_;
    int port_;
};

// 使用 Lambda 创建连接
ObjectPool<DatabaseConnection> connPool(
    5,
    []() {
        return DatabaseConnection("localhost", 3306);
    }
);

// 使用连接
DatabaseConnection conn = connPool.acquire();
conn.query("SELECT * FROM users");
connPool.release(std::move(conn));

与 FixedSizePool 的区别

特性 ObjectsPool FixedSizePool
类型 对象池 内存池
管理内容 对象实例 原始内存块
模板参数 template<typename T> 非模板
创建方式 通过 creator 函数 直接分配内存
返回类型 T(对象) void*(内存指针)
初始化 对象构造函数完成 使用 placement new
适用场景 复杂对象(如 YOLO 模型) 简单数据结构(如缓冲区)

注意事项

  1. 对象类型: 对象类型 T 必须支持移动语义
  2. 对象状态: 归还的对象可能包含之前的状态,使用前需要重置
  3. 池大小: 构造时确定池大小,运行时不能调整
  4. 阻塞等待: acquire() 会阻塞,确保池中有对象
  5. 超时处理: 使用 tryAcquire() 避免死锁
  6. 对象生命周期: 归还的对象会被复用,不要保留对象引用
  7. 线程安全: 多线程获取不同对象是安全的,同一对象需要外部同步
  8. 资源清理: 析构时释放所有对象,确保对象正确清理资源

相关文档


参考资料

主页

API 文档

DMA 模块

DRM 模块

NET 模块

V4L2 模块

V4L2Param 模块

RGA 模块

MPP 模块

Sys 模块

Mouse 模块

Utils 模块

Clone this wiki locally