QFutureWatcher, как смотреть несколько задач / фьючерсов и готовых () сигналов

У меня есть несколько задач, началось с QtConcurrent::run(),
Задачи имеет QFutureWatcher, я знаю это QFutureWatcher можно посмотреть только один Будущее, но когда я запускаю те же задачи из пользовательского интерфейса, как я могу создать `QFutureWatcher * для каждой задачи? Это :

QFutureWatcher<void> *watcher = new QFutureWatcher;
watcher->setFuture(future);
QVector<QFutureWatcher<void>*> watchers;
watchers.push_back(watcher); // vector with pointers to each tasks watchers

или что-то другое?
* Моя проблема является то, что я запускаю каждую задачу из своего кода, но задачи, выполняемые с внешними функциями DLL. И у меня нет API, чтобы остановить задачу. Я могу только ждать, пока задача закончилась, и закрыть задачу, отпустив все связанные данные, после того, как я получу, закончил QFutureWatcher сигнал.

В данный момент я использую два QFutureWatchers — один наблюдает за первым выполненным заданием, другой — запускается, если первое задание не закончилось, и наблюдаю за вторым заданием с помощью временного наблюдателя и временный слот (код тот же, я создаю его только для получения другого сигнала наблюдателя со связанными данными), пока не закончится первая задача. И он смотрел тот же код, но я должен продублировать его, чтобы дождаться, когда первое задание закончено, потому что QFutureWatcher не имеет очереди с законченными сигналами и связанными watcher.result () `s ..

1) Есть ли в Qt какой-либо механизм задач в очереди? или как я могу поймать несколько задач на будущее?

2) QtConcurrent::run не имеет слота cancel (). Могу ли я использовать функции map / mapped с одним элементом последовательности? Имеет ли отображенный API очередь обработки задач / завершенных сигналов? Как я могу это понять? Спасибо!

2

Решение

1) Вы можете использовать что-то вроде этого (просто черновик кода):

class MultiWatcher
: public QThread
{
Q_OBJECT

signals:
void allDone();

public:
void run() override;
QFutureSynchronizer _sync;
};

void MultiWatcher::run()
{
_sync.waitForFinished();
emit allDone();
}class Test
: public QObject
{
Q_OBJECT
public:
//...
void do();
void onDone();
};

void Test::do()
{
// fill some futures
auto w = new MultiWatcher();
w->_sync.addFuture( f1 ); // Not thread-safe
w->_sync.addFuture( f2 );
w->_sync.addFuture( f3 );
// ...
connect( w, &MultiWatcher::allDone, this, &Test::onDone );
w->start();
}

void Test::onDone()
{
sender()->deleteLater();
qDebug() << "All futures are done";
}

//...
test->do();

2) есть QFuture::cancel() Метод для сопоставленных расчетов. Из вашего вопроса непонятно, как вы получаете фьючерсы, поэтому сложно сказать больше. Вы можете прочитать о параллелизм в Qt и задавайте больше вопросов, если они у вас будут.

QFuture::cancel не будет работать с QtConcurrent::runвам нужно спроектировать другой механизм прерывания внутри вашего потока кода. Например:

std::atomic_bool _isRunning = true; // somewhere in code

void MyWorker::doWork()
{
while (_isRunning)
{
// Do next step of computation
}
}

// Use _isRunning = false; to interrupt. It's thread-safe.

Но рискованно прерывать код, которым вы не управляете (из внешних .dll), потому что у вас может быть много утечек. Вот почему в QtConcurrent нет API завершения.

Постскриптум Пожалуйста, не пишите это Я делаю это неправильно с QThread. Там все хорошо. Я знаю, что я делаю. Это хороший образец, где наследование QThread все в порядке.

3

Другие решения

Есть ли в Qt какой-либо механизм задач в очереди?

Qt предоставляет мощный сигнал&слот каркаса, который идеально подходит для такого применения.

Шаги реализации:

  1. Создайте рабочий класс (производный от QObject), в котором есть слот executeTask(int foo, QString bar) который содержит реализацию задачи.
  2. Создать QThread и переместите ваш экземпляр класса Worker в этот QThread, используя QObject::moveToThread
  3. Начать тему
  4. Запускайте задачи, испуская сигнал, который подключен к executeTask или по телефону QMetaMethod::invoke на executeTask метод.

Заметки:

  • Qt поставит ваши звонки в очередь executeTask (при условии, что вы используете один из методов, описанных в 4.), и они будут выполняться по порядку.
  • Чтобы быстро терминировать вашего работника, вы можете использовать QThread::requestInterruption и проверьте отмену в вашем executeTask метод с использованием QThread::isInterruptionRequested,
  • Для принудительного увольнения вашего работника вы можете использовать QThread::terminate,
  • В противном случае используйте QThread::quit а также QThread::wait изящно уволить работника и ждать, пока все задачи не будут выполнены.
1

По вопросам рекламы [email protected]