2

Background

In my Qt5.3 application I deal with several time consuming processes (statistical computations). In order to be able to operate with application, while one or more computations are running, I created class called ProgressManager. This manager registers computation objects that inherit from abstract class IRunnable and implement pure virtual method run.

Each time a new time-consuming operation is started, it is registered in ProgressManager connected to its progressbar and started through following function:

void ProgressManager::runProgress(const QVariant &id, const QVariant &param) {

  // If progress is not present, exit
  if (!progs.contains(id)) {
    return;
  }

  // If progress is not runnable, exit
  IRunnable* runnable = dynamic_cast<IRunnable*>(progs.value(id));
  if (!runnable) {
    return;
  }

  // Create future watcher
  QFutureWatcher<QVariant>* watcher = new QFutureWatcher<QVariant>();
  connect(watcher, SIGNAL(finished()), this, SLOT(handleFinished()));

  // Register running progress
  running.insert(watcher, id);

  // Paralelize runnable progress
  QFuture<QVariant> future = QtConcurrent::run(runnable, &IRunnable::run, param);
  watcher->setFuture(future);
}

After parallel process finishes following function should be called:

void ProgressManager::handleFinished() {

  // Retrieves sender watcher
  QObject* s = this->sender();
  QFutureWatcher<QVariant>* w = dynamic_cast<QFutureWatcher<QVariant>*>(s);

  // Retrieve ID of running progress and delete watcher
  QVariant id = running.value(w);
  running.remove(w);
  delete w;

  // Emit progress has finished
  emit finished(id);
}

Problem

Everything is running smoothly until end of paralelized process is reached. Then application crashes everytime with segmentation fault, before calling finished signal and handleFinished slots.

Crash is reported in file qfutureinterface.h in function reportResults on line 211 where function is reportResultsReady called:

194 template <typename T>
195 inline void QFutureInterface<T>::reportResult(const T *result, int index)
196 {
197     QMutexLocker locker(mutex());
198     if (this->queryState(Canceled) || this->queryState(Finished)) {
199         return;
200     }
201 
202     QtPrivate::ResultStore<T> &store = resultStore();
203 
204 
205     if (store.filterMode()) {
206         const int resultCountBefore = store.count();
207         store.addResult(index, result);
208         this->reportResultsReady(resultCountBefore, resultCountBefore + store.count());
209     } else {
210         const int insertIndex = store.addResult(index, result);
211         this->reportResultsReady(insertIndex, insertIndex + 1);
212     }
213 }
Michal
  • 1,955
  • 5
  • 33
  • 56

1 Answers1

1

I have a similar problem. Currently, I am using QFutureInterface without using QtConcurrent and I am manually reporting that the QFuture is ready. For some reason I get crashes from time to time when QFutureInterface class' functions are called from different threads meaning QFutureInterface is probably not reentrant which automatically leads to the fact that it is not thread-safe despite the fact there are mutexes in its code, etc. There is no Qt doc about it no matter it is an exported class. I've taken wysota's approach commented here that one should look at QtConcurrent's sources about custom usage of QFutureInterface but probably there is something wrong with QFutureInterface's code if crashes when being used even by QtConcurrent. I'm using Qt 5.3.2.

Ivan Caravanio
  • 597
  • 1
  • 7
  • 20