C++调用多线程DLL,多线程调用回调函数

C++ DLL回调问题
本文探讨了在C++中调用DLL内的函数并传递回调函数(委托)时遇到的堆栈溢出问题。通过调整调用约定,解决了回调后堆栈不平衡导致的崩溃。
【情景】
在C++代码中要调用C++编写的dll中的一个函数,并传递一个回调函数(很明显,这里应该传递一个委托),C++函数在内部通过一个额外的线程在后台运行,完成工作后通过这个回调函数通知前台的C++代码。。。。
【问题】
在经过很长时间的混合调试后发现,回调函数(也就是C++中传递的委托)能顺利被调用,然后返回C++代码,然后vs就会提示缓冲区溢出或者堆栈之类的错误,程序崩溃。如果不是单步跟踪到dll调试的话,程序运行到此处便会直接退出,毫无提示,只在C++中调试是发现不了的!
方法一、
typedef void (CALLBACK *CopyFileNotify)  (int);
问题的原因,应该默认的调用约定和dll函数的约定不一致,回调函数返回后导致堆栈不平衡

方法二:
typedef void (CALLBACK* NOTIFYPROC)(LPVOID, ClientContext*, UINT nCode);
定义函数指针 对应的函数原型为 void __stdcall notifyproc(lpvoid, clientcontext*, uint);
C++ 多线程 DLL调用回调函数,核心在于利用多线程的并发能力,同时结合 DLL 的动态链接特性,实现灵活的回机制。基本方法是先定义回调函数类型,然后在 DLL 中注册和触发回调函数。 ### 实现步骤 1. **定义回调函数类型**:使用 `typedef` 或 `using` 定义回调函数的类型。 2. **在 DLL 中注册回调函数**:在 DLL 中提供一个函数,用于注册回调函数。 3. **在 DLL 中触发回调函数**:在 DLL 的某个线程中触发回调函数。 4. **在主程序中使用 DLL**:加载 DLL,注册回调函数,并触发相关操作。 ### 示例代码 #### DLL 代码(`callback_dll.cpp`) ```cpp #include <iostream> #include <vector> #include <thread> #include <windows.h> // 定义回调函数的类型 typedef void (*Callback)(const std::string&); // 存储回调函数的向量 std::vector<Callback> callbacks; // 注册回调函数 extern "C" __declspec(dllexport) void registerCallback(Callback callback) { callbacks.push_back(callback); } // 触发事件的线程函数 void eventThread() { while (true) { std::this_thread::sleep_for(std::chrono::seconds(2)); for (auto& callback : callbacks) { callback("Event triggered from DLL!"); } } } // 初始化 DLL 时启动线程 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: std::thread(eventThread).detach(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } ``` #### 主程序代码(`main.cpp`) ```cpp #include <iostream> #include <windows.h> // 定义回调函数的类型 typedef void (*Callback)(const std::string&); // 定义注册回调函数的类型 typedef void (*RegisterCallback)(Callback); // 定义一个回调函数 void logMessage(const std::string& message) { std::cout << "Logged: " << message << std::endl; } int main() { // 加载 DLL HINSTANCE hDll = LoadLibrary("callback_dll.dll"); if (hDll == NULL) { std::cerr << "Failed to load DLL." << std::endl; return 1; } // 获取注册回调函数的地址 RegisterCallback registerCallback = (RegisterCallback)GetProcAddress(hDll, "registerCallback"); if (registerCallback == NULL) { std::cerr << "Failed to get function address." << std::endl; FreeLibrary(hDll); return 1; } // 注册回调函数 registerCallback(logMessage); // 等待用户输入以退出 std::cin.get(); // 卸载 DLL FreeLibrary(hDll); return 0; } ``` ### 代码解释 1. **DLL 代码**: - 定义了回调函数类型 `Callback`。 - 提供了 `registerCallback` 函数,用于注册回调函数。 - 在 `DllMain` 函数中启动一个线程,该线程每隔 2 秒触发一次回调函数。 2. **主程序代码**: - 加载 DLL。 - 获取 `registerCallback` 函数的地址。 - 注册回调函数 `logMessage`。 - 等待用户输入以退出程序。 - 卸载 DLL。 ### 注意事项 - 确保 DLL 和主程序中定义的回调函数类型一致。 - 在多线程环境中,要注意线程安全问题,避免竞态条件。 - 处理 DLL 加载和卸载的错误情况。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值