QPluginLoader::instance() 的无限递归循环
Infinite recursive loop with QPluginLoader::instance()
我有一个概念上的问题想讨论一下。首先,我制作了一个插件加载自动系统,其工作原理如下:
1) 给出了要查找的插件文件名或路径。
2) 然后可以使用接口指针对其进行查询,并在找到时将其转换为合适的插件(可选地附加条件)。
查找实现的模板函数如下所示:
template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
tInterface *interface = nullptr;
for(QPluginLoader *loader : loaders(req)) //returns list of plugins that meet requirements in req
{
interface = qobject_cast<tInterface*>(loader.instance())
if(interface)
break;
}
return interface;
}
根据 Qt 文档,插件 instance()
(返回根组件)应该在所有操作同一文件的 QPluginLoader 对象之间 "shared"。好吧,我发现事实并非如此。当从插件构造函数(或在根构造函数调用的任何构造函数)中调用它时,上面的代码将无限循环。因为这样的调用将实例化同一个插件(以及其他插件)来测试请求的实现,这将触发另一个调用等等。只有在插件构造函数之外调用时它才能正常工作...
我正在尝试找出一种解决方案,即使在插件的构造函数中也能使用它。到目前为止,我想不出一种方法或机制来停止循环,因此我的问题在这里。感谢您的任何想法!
好的,答案很简单。当前调用 instance()
的 QPluginLoader 对象必须在调用 instance()
之前 "locked" 以便在第一次调用完成之前禁止对其实例的后续调用 - 有点像互斥行为。这可以防止在同一 QPluginLoader 上对 instance()
的调用中调用 instance()
所描述的问题(发生是因为搜索所有插件以寻找接口的可能实现,请参阅 OP 了解执行此操作的功能) .
我通过跟踪 "in use" 在 instance()
完成后释放它们的 QPluginLoader 对象来完成它。这允许我在其他插件的构造函数中请求插件,唯一的限制是我不能在加载层次结构中请求相同的插件或任何 "parent" 插件:
如果插件 X 的构造函数请求插件 Y,而插件 Y(在其构造函数中)请求插件 Z,则 Z 不能在其自己的构造函数中请求 Y 或 X(并且 Y 不能请求 X)。此类尝试将无法返回 nullptr 接口。
为了完整起见,这里是修改后的函数:
template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
tInterface *interface = nullptr;
for(QPluginLoader *loader : loaders(req))
//loaders() returns list of plugins that meet requirements in req
//AND ARE NOT PRESENT IN m_Locked
{
m_Locked << loader;
interface = qobject_cast<tInterface*>(loader.instance())
m_Locked.removeOne(loader);
if(interface)
break;
}
return interface;
}
我有一个概念上的问题想讨论一下。首先,我制作了一个插件加载自动系统,其工作原理如下:
1) 给出了要查找的插件文件名或路径。
2) 然后可以使用接口指针对其进行查询,并在找到时将其转换为合适的插件(可选地附加条件)。
查找实现的模板函数如下所示:
template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
tInterface *interface = nullptr;
for(QPluginLoader *loader : loaders(req)) //returns list of plugins that meet requirements in req
{
interface = qobject_cast<tInterface*>(loader.instance())
if(interface)
break;
}
return interface;
}
根据 Qt 文档,插件 instance()
(返回根组件)应该在所有操作同一文件的 QPluginLoader 对象之间 "shared"。好吧,我发现事实并非如此。当从插件构造函数(或在根构造函数调用的任何构造函数)中调用它时,上面的代码将无限循环。因为这样的调用将实例化同一个插件(以及其他插件)来测试请求的实现,这将触发另一个调用等等。只有在插件构造函数之外调用时它才能正常工作...
我正在尝试找出一种解决方案,即使在插件的构造函数中也能使用它。到目前为止,我想不出一种方法或机制来停止循环,因此我的问题在这里。感谢您的任何想法!
好的,答案很简单。当前调用 instance()
的 QPluginLoader 对象必须在调用 instance()
之前 "locked" 以便在第一次调用完成之前禁止对其实例的后续调用 - 有点像互斥行为。这可以防止在同一 QPluginLoader 上对 instance()
的调用中调用 instance()
所描述的问题(发生是因为搜索所有插件以寻找接口的可能实现,请参阅 OP 了解执行此操作的功能) .
我通过跟踪 "in use" 在 instance()
完成后释放它们的 QPluginLoader 对象来完成它。这允许我在其他插件的构造函数中请求插件,唯一的限制是我不能在加载层次结构中请求相同的插件或任何 "parent" 插件:
如果插件 X 的构造函数请求插件 Y,而插件 Y(在其构造函数中)请求插件 Z,则 Z 不能在其自己的构造函数中请求 Y 或 X(并且 Y 不能请求 X)。此类尝试将无法返回 nullptr 接口。
为了完整起见,这里是修改后的函数:
template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
tInterface *interface = nullptr;
for(QPluginLoader *loader : loaders(req))
//loaders() returns list of plugins that meet requirements in req
//AND ARE NOT PRESENT IN m_Locked
{
m_Locked << loader;
interface = qobject_cast<tInterface*>(loader.instance())
m_Locked.removeOne(loader);
if(interface)
break;
}
return interface;
}