2015-04-01 33 views
0

我有一个概念问题,我想讨论一下。首先,我制作了一个插件加载的自动系统,它的工作原理如下:使用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对象之间应该是“共享”。那么我发现情况并非如此。上面的代码在插件构造函数(或者任何由根函数调用的构造函数)中进行调用时会无限循环。因为这样的调用将会实例化同一个插件(等等)来测试将要触发另一个调用的请求实现等等。它只能在插件构造函数之外调用时才能正常工作......

我想找出一个解决方案,即使在插件的构造函数中也可以使用它。到目前为止,我想不出一种方法或机制来阻止循环,因此我的问题在这里。感谢您的任何想法!

+1

我不完全理解 - 你说,你的插件的构造函数被调用反复代码,其中再次加载相同的插件?为什么你甚至想要插件从构造函数中周期性地加载插件? – Googie 2015-04-01 07:47:29

+0

@Googie好吧,它无意中。基本上我这样做:加载插件X与这个代码,在它的构造函数加载插件Y使用此函数。并且因为该函数以某种方式工作,以便加载每个可用插件并根据请求的接口对其进行测试,它可能会(无意中)加载调用它的构造函数等创建循环的同一个插件。 – Resurrection 2015-04-01 07:56:03

+1

每个插件文件应该只有一个'QPluginLoader'。这样你可以跟踪加载的插件。另外,我认为你误解了Qt文档中关于多个'QPluginLoader'实例中插件的“共享实例”。 Qt文档只告诉你,每次调用同一个装载器的'QPluginLoader :: instance()'时,你都会得到同样的插件对象。如果您使用两个不同的插件加载器加载插件,则最终会有两个不同的插件实例。所以......为每个插件和轨道装载机保留一个加载程序。 – Googie 2015-04-01 08:24:34

回答

0

好,所以答案很简单。当前调用的QPluginLoader对象在instance()之前必须被“锁定”,以便在第一次调用完成之前禁止后续实例调用 - 对互斥行为进行排序。这可以防止在调用instance()时在同一个QPluginLoader中调用instance()所述的问题(由于搜索所有插件寻找接口的可能实现,请参阅OP了解实现该功能的函数)。

我完成它跟踪在instance()完成后释放它们的“使用中”的QPluginLoader对象。这允许我在其他插件的构造函数中请求插件,唯一的限制是我无法在加载层次中请求相同的插件或任何“父”插件:

如果插件X的构造函数请求插件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; 
}