ACE_Thread_Manager和WinMain冲突问题

本文探讨了在Windows程序中使用ACE_Thread_Manager创建线程时遇到的崩溃问题,并通过对比发现是由于WinMain函数未进行正确的ACE初始化所导致。通过手动调用ACE::init()解决了该问题。
部署运行你感兴趣的模型镜像
今天在一个Windows的程序中使用了ACE_Thread_Manager::instance ()->spawn来创建新的线程,结果发现程序崩溃。然后改用ACE_Thread::spawn后确发现没有问题,为什么会这样呢?

--------------------------------------------------
author: cs_cjl
website:  http://blog.csdn.net/cs_cjl
--------------------------------------------------

第一时间想到的是使用StackWalker打印崩溃的堆栈信息:
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 779B22D2)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 779B22D2 (ntdll): (filename not available): RtlEnterCriticalSection
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 0FFF6D9D)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 0FFF6D9D (ACEd): (filename not available): ACE_OS::thread_mutex_lock
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 100304D0)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 100304D0 (ACEd): (filename not available): ACE_Thread_Mutex::acquire
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 0FF7B8F3)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 0FF7B8F3 (ACEd): (filename not available): ACE_Task<ACE_NULL_SYNCH>::dump
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 0FF77131)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 0FF77131 (ACEd): (filename not available): ACE_Task<ACE_NULL_SYNCH>::dump
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 10029C5D)
Dec 03 18:43:27.807 2013@LM_EMERGENCY@ (8808) 10029C5D (ACEd): (filename not available): ACE_Thread_Exit::instance
Dec 03 18:43:27.808 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 10029853)
Dec 03 18:43:27.808 2013@LM_EMERGENCY@ (8808) 10029853 (ACEd): (filename not available): ACE_Thread_Adapter::invoke
Dec 03 18:43:27.813 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 0FFA6B99)
Dec 03 18:43:27.813 2013@LM_EMERGENCY@ (8808) 0FFA6B99 (ACEd): (filename not available): ace_thread_adapter
Dec 03 18:43:27.813 2013@LM_EMERGENCY@ (8808) f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c (314): _callthreadstartex
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c (297): _threadstartex
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 75B1336A)
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) 75B1336A (kernel32): (filename not available): BaseThreadInitThunk
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 779C9F72)
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) 779C9F72 (ntdll): (filename not available): RtlInitializeExceptionChain
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) OnDbgHelpErr: SymGetLineFromAddr64, GetLastError: 487 (Address: 779C9F45)
Dec 03 18:43:27.814 2013@LM_EMERGENCY@ (8808) 779C9F45 (ntdll): (filename not available): RtlInitializeExceptionChain

然后查看之前写的程序,发现也是调用了ACE_Thread_Manager却不会出现崩溃的问题,对比了一下,发现之前写的程序用的是main函数而不是WinMain,在这里试了好久后,突然想到对于main函数,ACE会将其替换为ACE的main函数然后执行一系列初始化操作后再调用我们的main,那么会不会是因为由于ACE不会替换WinMain从而导致ACE中的一些初始化没有执行导致ACE_Thread_Manager崩溃呢?

google了一下,发现网上的说法是,如果是WinMain需要在开头手动调用
Init_ACE.h中的ACE::init(),试了一下果然不会崩溃了。

那么ACE自己的main函数中到底执行了什么操作呢?
查啊查发现主要执行以下操作(在OS_main.cpp中):
ACE::init ();
ACE_MAIN_OBJECT_MANAGER
int const i = this->run_i (ce_argv.argc (), ce_argv.argv ());
ACE::fini ();
return i;

原来如此!!!
至于ACE::init()到底做了什么初始化操作呢?请自行查看

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### 问题分析 报错信息 `relocation truncated to fit: R_X86_64_PC32 against undefined symbol 'WinMain'` 通常出现在链接阶段,表示链接器在尝试生成可执行文件时,发现符号 `WinMain` 未被定义,并且尝试进行重定位时发生了截断错误。此问题常见于 Windows 平台使用 GCC 或 MinGW 编译器时,尤其是在混合使用控制台图形界面链接器选项的情况下。 ### 常见原因与解决方法 1. **入口点选择错误** Windows 应用程序有两种主要的入口模式: - 控制台应用程序使用 `main` 函数作为入口点。 - 图形界面应用程序使用 `WinMain` 函数作为入口点。 如果编译器或链接器被配置为期望 `WinMain` 作为入口函数,但源代码中并未定义该函数,则会报出 `undefined symbol 'WinMain'` 错误[^2]。 **解决方法**:确保你的项目类型与入口函数匹配。如果你正在编写控制台程序,请确保使用 `main` 函数,并在链接时指定控制台子系统。例如,使用 MinGW 编译时可以添加 `-mconsole` 选项: ```bash gcc main.c -o main.exe -mconsole ``` 2. **显式指定入口函数** 如果你希望使用自定义入口函数(例如 `WinMain`),但链接器未能正确识别,可以通过链接器参数显式指定入口点。例如,使用 MinGW 时可以添加如下参数: ```bash gcc main.c -o main.exe -Wl,--entry,WinMainCRTStartup ``` 或者,在代码中使用 `#pragma comment` 指令指定子系统入口函数: ```c #pragma comment(linker, "/subsystem:windows /entry:WinMainCRTStartup") ``` 如果你确实希望使用 `main` 函数而不是 `WinMain`,则应使用 `/subsystem:console` 并省略 `/entry` 参数,或将其设置为 `mainCRTStartup`[^3]。 3. **避免混合使用子系统入口点配置** 某些项目中可能会同时包含 `/subsystem:windows` 尝试使用 `main` 函数,这会导致链接器期望 `WinMain` 而实际提供了 `main`,从而引发符号未定义错误。 **解决方法**:确保子系统与入口函数一致。例如: - 控制台程序: ```c #pragma comment(linker, "/subsystem:console") int main() { return 0; } ``` - Windows 程序: ```c #pragma comment(linker, "/subsystem:windows") int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return 0; } ``` 4. **使用 `-fPIC` 编译共享库** 如果你正在构建共享对象(`.so` 或 `.dll`),并且遇到类似 `relocation R_X86_64_PC32` 的错误,这通常是因为未使用位置无关代码(Position Independent Code, PIC)进行编译。 **解决方法**:在编译命令中添加 `-fPIC` 选项: ```bash gcc -fPIC -c mylib.c gcc -shared -o libmylib.so mylib.o ``` 这可以避免某些架构下的重定位限制问题[^1]。 5. **检查编译器与链接器版本一致性** 如果你使用的是 Cygwin、MinGW 或 MSVC 的混合环境,不同工具链之间的库链接方式可能存在不兼容问题。例如,Cygwin 的 `gcc` 默认链接 Windows 子系统的方式可能与原生 MinGW 不同。 **解决方法**:确保使用统一的编译器链接器工具链。例如,若你希望构建原生 Windows 程序,请使用 MinGW 或 MSYS2 环境下的 `x86_64-w64-mingw32-gcc`。 ### 总结 报错 `relocation truncated to fit: R_X86_64_PC32 against undefined symbol 'WinMain'` 的核心问题是链接器在尝试解析入口函数时未能找到正确的符号,并且在尝试重定位时发生了地址截断。解决该问题的关键在于确保入口函数与子系统配置一致,并在必要时显式指定链接器选项。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值