找回密码
 立即注册
首页 业界区 安全 “静态回调+上下文指针”模式实现回调机制 ...

“静态回调+上下文指针”模式实现回调机制

嫂潍 昨天 23:00
0 摘要

以常用的某品牌相机的驱动为例,分析回调机制的实现。
1 SetCallback(即,注册回调)的实现

1.1 函数签名
  1. int MV_CC_RegisterImageCallBackEx(
  2.     void* handle,                           // 相机设备句柄
  3.     void (__stdcall *pCallBack)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser),  // 回调函数指针
  4.     void* pUser                             // 用户自定义数据
  5. );
复制代码
参数说明

  • handle:相机设备句柄,用于标识具体的相机设备
  • pCallBack:回调函数指针,使用__stdcall调用约定
  • pUser:用户数据(即,上下文指针),会在回调时原样传回
1.2 内部实现
  1. // 内部数据结构
  2. struct CameraDevice {
  3.     void* hardwareHandle;           // 硬件设备句柄
  4.     void* userCallback;            // 用户回调函数指针
  5.     void* userData;                // 用户数据
  6.     std::thread* captureThread;    // 采集线程
  7.     bool isGrabbing;               // 采集状态
  8.     // ... 其他成员
  9. };
  10. // 函数实现
  11. int MV_CC_RegisterImageCallBackEx(void* handle,
  12.                                   void (__stdcall *pCallBack)(unsigned char *, MV_FRAME_OUT_INFO_EX*, void*),
  13.                                   void* pUser) {
  14.     // 1. 参数验证
  15.     if (!handle || !pCallBack) {
  16.         return MV_E_PARAMETER;  // 参数错误
  17.     }
  18.    
  19.     // 2. 获取设备对象
  20.     CameraDevice* device = static_cast<CameraDevice*>(handle);
  21.    
  22.     // 3. 保存回调函数和用户数据
  23.     device->userCallback = reinterpret_cast<void*>(pCallBack);
  24.     device->userData = pUser;
  25.    
  26.     // 4. 返回成功
  27.     return MV_OK;
  28. }
复制代码
2 回调触发机制
  1. // 采集线程
  2. void CaptureThreadProc(CameraDevice* device) {
  3.     while (device->isGrabbing) {
  4.         // 1. 从硬件获取图像数据
  5.         unsigned char* imageData = nullptr;
  6.         MV_FRAME_OUT_INFO_EX frameInfo = {0};
  7.         
  8.         int result = GetImageFromHardware(device->hardwareHandle, &imageData, &frameInfo);
  9.         
  10.         if (result == MV_OK && imageData != nullptr) {
  11.             // 2. 检查是否有注册的回调函数
  12.             if (device->userCallback) {
  13.                 // 3. 调用用户回调函数
  14.                 auto callback = reinterpret_cast<void (__stdcall *)(unsigned char *, MV_FRAME_OUT_INFO_EX*, void*)>
  15.                                (device->userCallback);
  16.                
  17.                 // 4. 在单独的线程或当前线程中执行回调
  18.                 callback(imageData, &frameInfo, device->userData);
  19.             }
  20.         }
  21.         
  22.         // 5. 短暂休眠,避免过度占用CPU
  23.         std::this_thread::sleep_for(std::chrono::microseconds(100));
  24.     }
  25. }
  26. int MV_CC_StartGrabbing(void* handle) {
  27.     CameraDevice* device = static_cast<CameraDevice*>(handle);
  28.    
  29.     if (device->isGrabbing) {
  30.         return MV_E_CALLORDER;  // 已经在采集中
  31.     }
  32.    
  33.     // 启动采集线程
  34.     device->isGrabbing = true;
  35.     device->captureThread = new std::thread(CaptureThreadProc, device);
  36.    
  37.     return MV_OK;
  38. }
复制代码
3. 关键设计要点


  • 函数指针存储:SDK内部保存用户提供的回调函数指针
  • 用户数据传递:将用户数据原样保存,回调时传回
  • 线程安全:在采集线程中调用回调,需要考虑线程安全
  • 异常处理:回调执行异常不应影响采集线程的正常运行
4 实际应用中的考虑

4.1 性能考虑
  1. // 回调应该快速执行,避免阻塞采集线程
  2. void ImageCB(...) {
  3.     // 快速处理或提交到线程池
  4.     // 避免在回调中执行耗时操作
  5. }
复制代码
4.2 错误处理
  1. // SDK应该处理回调中的异常
  2. void CaptureThreadProc(CameraDevice* device) {
  3.     try {
  4.         if (device->userCallback) {
  5.             callback(imageData, &frameInfo, device->userData);
  6.         }
  7.     } catch (...) {
  8.         // 记录错误,但不影响采集线程
  9.         LogError("Callback execution failed");
  10.     }
  11. }
复制代码
4.3 资源管理
  1. // 确保回调中正确管理资源
  2. void ImageCB(...) {
  3.     // 使用智能指针或RAII管理临时资源
  4.     std::unique_ptr<unsigned char[]> buffer(pData);
  5.     // ... 处理逻辑 ...
  6.     // 自动释放内存
  7. }
复制代码
5 最佳实践的建议
  1. class Camera {
  2. private:
  3.     // 1. 静态桥接函数
  4.     static void __stdcall CallbackBridge(/* 参数 */, void* userData) {
  5.         // 参数验证
  6.         if (!userData) return;
  7.         
  8.         // 恢复对象指针
  9.         Camera* self = static_cast<Camera*>(userData);
  10.         
  11.         // 异常处理
  12.         try {
  13.             self->HandleCallback(/* 参数 */);
  14.         } catch (...) {
  15.             // 错误处理
  16.         }
  17.     }
  18.    
  19.     // 2. 实际处理函数(非静态)
  20.     void HandleCallback(/* 参数 */) {
  21.         // 直接访问成员变量
  22.         // 实现业务逻辑
  23.     }
  24.    
  25.     // 3. 注册回调
  26.     void RegisterCallback() {
  27.         SDK_RegisterCallback(CallbackBridge, this);
  28.     }
  29. };
复制代码
这种设计既保持了与C风格API的兼容性,又能在实际处理函数(即,HandleCallback)中,获得面向对象编程的便利性。
6 相关设计模式

6.1 观察者模式(Observer Pattern)

回调机制本质上是观察者模式的简化版本:

  • Subject:相机SDK
  • Observer:用户回调函数
  • 通知机制:函数指针调用
6.2 策略模式(Strategy Pattern)

回调函数可以看作是可替换的算法策略:

  • Context:相机采集过程
  • Strategy:用户提供的处理函数
  • 执行时机:图像采集完成时
6.3 模板方法模式(Template Method)

SDK定义了采集的算法骨架,用户定义具体的处理步骤:

  • 模板方法:采集流程
  • 钩子方法:回调函数
7 总结

回调机制:

  • 注册机制:SDK保存用户提供的函数指针和上下文数据
  • 触发机制:在特定事件发生时调用保存的函数指针
  • 数据传递:通过参数将事件相关数据传递给回调函数
  • 上下文恢复:通过用户数据参数恢复调用上下文
回调机制在设备驱动、GUI框架、网络库,等领域广泛应用,是实现松耦合、事件驱动的重要工具。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册