QPluginLoader перемещен в поток

Я создаю приложение, которое будет в значительной степени полагаться на плагины: ядро ​​​​получает данные из последовательного интерфейса и доставляет их каждому плагину, чтобы каждый мог решить, что с ним делать.

Мой дизайн позволяет плагинам создавать виджет, который прикрепляется к MDIArea через QMdiSubWindow. Это работало до тех пор, пока мне не понадобились мьютексы, так как все работало в одном потоке, и я очень быстро получал взаимоблокировки. Поэтому я подумал, что перемещение каждого плагина в другой поток может решить эту проблему. Проблема в том, что (на данный момент) QMdiSubWindow больше не создается, и я понятия не имею, почему это происходит.

Ядро взаимодействует с плагинами с помощью сигналов и слотов.

Вот как я загружаю свои плагины и перемещаю их в поток:

QPluginLoader loader( the_path );
QObject* plugin = loader.instance();
if( plugin!=0 )
{
    //Connect install subwindows request
    connect( plugin, SIGNAL(install_plugin_window(QString,QWidget*)), this, SLOT(onRequestInstallSubwindow(QString,QWidget*)) );

    QThread* consumer = new QThread;
    plugin->moveToThread( consumer );
    consumer->start();

    PluginInterface* pl = qobject_cast<PluginInterface*>(plugin);
    pl->registerSubWindow();
}

Обратите внимание, что это упрощение исходного кода. Я следовал этому подходу (перемещая свой плагин в поток) на основе этой статьи http://www.christeck.de/wp/2010/10/23/the-great-qthread-mess/

registerSubWindow() — это метод в моем плагине, который создает виджет:

void PluginDrier::registerSubWindow()
{
    widget = new Form();
    emit install_plugin_window( "Plugin Widget", widget );
}

Который излучает сигнал, который улавливается ядром с этим слотом, который регистрирует сгенерированный виджет как упомянутый MdiSubWindow:

void MainWindow::onRequestInstallSubwindow( QString title, QWidget* content )
{
    QMdiSubWindow* subwindow = ui->mdiArea->addSubWindow( content );
    subwindow->setWindowTitle( title );
    subwindow->setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowTitleHint |     Qt::WindowMinMaxButtonsHint );
}

person Pherrymason    schedule 20.07.2011    source источник


Ответы (1)


Виджеты Qt работают только в потоке GUI. Вы можете попытаться переместить внутренние операции плагина в другие потоки, но весь графический интерфейс должен оставаться в вашем основном потоке.

Попробуй это:

void PluginDrier::registerSubWindow()
{
    widget = new Form();
    widget->moveToThread(QApplication::instance()->thread ());
    emit install_plugin_window( "Plugin Widget", widget );
}

но я не проверял, может не сработать. Кроме того, имейте в виду, что все связи между вашей внутренней логикой и графическим интерфейсом должны быть потокобезопасными, если мое решение будет работать.

person Raiv    schedule 20.07.2011
comment
Могу ли я лучше переместить виджет в поток GUI в onRequestInstallSubwindow()? - person Pherrymason; 20.07.2011
comment
Возникает вопрос: учитывая, что виджеты должны находиться в основном потоке, какова ценность их создания в отдельных потоках? Мне кажется, было бы лучше перенести чтение данных в другой поток, а все операции с графическим интерфейсом оставить в основном. - person Dan Milburn; 20.07.2011
comment
Как я мог тогда разделить свои плагины на две части? Может быть, включить рабочий объект внутри моего плагина, который будет содержать всю внутреннюю логику и передавать этот рабочий объект в новый поток? - person Pherrymason; 20.07.2011
comment
@clinisbut ›Могу ли я лучше переместить виджет в поток графического интерфейса в onRequestInstallSubwindow()? - Нет, вы не можете, эта операция должна выполняться в потоке, в котором вы создаете свой объект. - person Raiv; 20.07.2011
comment
@clinis, да. идея с рабочим объектом хороша, вы можете сделать это. - person Raiv; 20.07.2011