【发布时间】:2020-04-10 06:07:03
【问题描述】:
我正在创建一个驻留在 DLL 中的 COM 类(带有 ATL)。对于我的成员函数之一,根据某些条件,我可能会使用必须初始化和终止的第三方库(Adobe 的 XMP SDK)。所以基本上,我会有一个看起来像这样的成员函数:
void CMyClass::MyMemberFunction()
{
SXMPMeta::Initialize();
// ...
SXMPMeta::Terminate();
}
现在根据 Adobe XMP 库文档,
你必须调用初始化和终止函数 单线程方式。 . . .
同时,我相信文件资源管理器可能会在不同的线程上创建我的类的多个实例。所以如果我理解正确,听起来我会有一个关键部分,我需要在库初始化和终止周围使用互斥锁(但如果有错误请纠正我)。
我不清楚该怎么做。我不确定我是否应该使用ATL critical section classes 之一或者可能是CRITICAL_SECTION。 CRITICAL_SECTION 似乎是一个不错的选择,但 example 显示它正在 main() 中初始化。如果您在 DLL 中会发生什么?我不想开始弄乱 DllMain()。任何帮助或想法将不胜感激。
根据 Gem 的建议,我尝试了以下方法:
struct XMPLibraryInitializer
{
XMPLibraryInitializer()
{
// Initialize libraries
if (!SXMPMeta::Initialize() || !SXMPFiles::Initialize())
{
XMP_StringPtr pszErrorMessage = "Libraries failed to load";
throw XMP_Error(kXMPErr_InternalFailure, pszErrorMessage);
}
ATLTRACE("\nXMP library initialized on thread %lu\n", GetCurrentThreadId());
}
~XMPLibraryInitializer()
{
// Terminate XMP libraries
SXMPFiles::Terminate();
SXMPMeta::Terminate();
ATLTRACE("\nXMP library terminated on thread %lu\n", GetCurrentThreadId());
}
};
HRESULT MyFunc()
{
// Statically initialize the Adobe XMP library
try
{
static XMPLibraryInitializer xmpLibraryInitializer;
}
catch (const XMP_Error & e)
{
return E_UNEXPECTED;
}
// ...
}
这似乎运行良好,除了我看到的输出是
XMP 库在线程 5820 上初始化 ... XMP 库在线程 3104 上终止
对于不同的线程号有什么解释吗?如果数字不同,是否意味着它不符合要求单线程初始化和终止的文档?
【问题讨论】:
-
Explorer 不这样做,它不需要扩展是线程安全的。主要是因为这会使正确编写 shell 扩展变得非常困难。所以它自己处理它,确保所有调用都来自同一个线程(又名“公寓线程”)。
-
哦,那也许我的整个前提是错误的。为了测试它,我从班级的 FinalConstruct() 中打印了 GetCurrentThreadId(),它似乎打印出了几个不同的数字。你知道为什么会这样吗?附加信息:我的类是一个属性处理程序,我导航到一个包含一堆不同文件的文件夹以获取读数。附加信息:我是新手,所以我不太清楚自己在做什么。
-
所以可能发生的情况是,它是在第一次使用时在碰巧的任何线程上构建的,然后在程序退出时被破坏,这很可能是程序的主线程,尽管有很多讨论它是否可能是程序的最后退出线程,通常是主线程,但不一定适用于所有架构。通常这对于需要以“单线程/线程保存”方式初始化但可以在多个线程上使用的对象来说已经足够了。如果要从多个线程中使用,则该对象不能保持任何线程特定的状态。
-
好的,只要它不泄漏资源或导致崩溃,我很满意。非常感谢您的帮助。