What is the proper way to build a signal / slot wrapper for a blocking call?

Suppose I also have QObjecta blocking method (say, this is a library call that must return a large amount of data from the network before returning).

class Foo : public QObject { 
Bar* _bar;
public:
    // non blocking call, emits stuffDone when done
    void startStuff(int a, int b);
signals:
    void stuffDone(int sum);
}


class Bar {
public:
    // Blocking call
    int doStuff(int a, b) { 
        for(int i=0; i<=100000000000; i++);
        return a + b;
    }
}

I would like my Foo::startStuffmethod to start doStuffin the appropriate (separate) thread and trigger the signal stuffDoneafter completion. startStuffmust return immediately.

Bar can be a QObject, if necessary, which allows you to set the affinity of the thread through moveToThread

What is the easiest and most idiomatic way (Qt-like)?

+1
source share
1 answer

QtConcurrent::run, , :

struct Bar {
   // Blocks for 3 seconds
   int doStuff(int a, b) { 
      QThread::sleep(3);
      return a+b+42;
   }
};

class Foo : public QObject {
   Q_OBJECT
   Bar _bar;
public:
   // Non-blocking, emits stuffDone when done
   void startStuff(int a, int b) {
      QtConcurrent::run([a,b,this]{
         auto result = _bar.doStuff(a,b);
         emit stuffDone(result);
      });
   }
   Q_SIGNAL void stuffDone(int sum);
};

Foo QFutureWatcher, IMHO , , - , .

QSharedPointer<Bar> bar { new Bar };
auto watcher = new QFutureWatcher<int>;
connect(watcher, &QFutureWatcher::finished, watcher, [watcher, bar]{
  watcher->deleteLater();
  int result = watcher->result();
  // use the result here
});
auto future = QtConcurrent::run(&Bar::doStuff, bar, 1, 2);
watcher->setFuture(future);

, "" , , , . , QThread::[|m|u]sleep.

+4

Source: https://habr.com/ru/post/1607209/


All Articles