title: How does QtConcurrent::run wind up on main thread?
body: <p>I've built a QFuture based asynchronous networking facade in my application. Roughly it works like this:</p>
  
  <pre><code>namespace NetworkFacade {
      QByteArray syncGet(const QUrl&amp; url) {
          QEventLoop l;
          QByteArray rc;
  
          get(url, [&amp;](const QByteArray&amp; ba) {
              rc = ba;
              l.quit();
          });
  
          l.exec();
          return rc;
      }
  
      void get(const QUrl&amp; url, const std::function&lt;void (const QByteArray&amp;)&gt;&amp; handler) {
          QPointer&lt;QNetworkAccessManager&gt; m = new QNetworkAccessManager;
  
          QObject::connect(m, &amp;QNetworkAccessManager::finished, [=, &amp;m](QNetworkReply *r) {
              QByteArray ba;
  
              if (r &amp;&amp; r -&gt; error() == QNetworkReply::NoError)
                  ba = r -&gt; readAll();
  
              m.clear();
  
              if (handler)
                  handler(ba);
          });
          m -&gt; get(QNetworkRequest(url));
      }
  }
  </code></pre>
  
  <p>I have a <code>QTimer</code> that triggers a call on the main thread that does the following (obviously simplified):</p>
  
  <pre><code>foreach(Request r, requests) {
      futures.push_back(get(r));
  }
  
  foreach(QFuture&lt;SomeType&gt; f, futures) {
      f.waitForFinished();
      [do stuff with f.result()]
  }
  </code></pre>
  
  <p>My assumption was that <code>waitForFinished()</code> would block the main thread while background thread(s) executed my network requests. Instead I get a <code>qFatal</code> error:</p>
  
  <pre><code>ASSERT: "m_blockedRunLoopTimer == m_runLoopTimer" in file eventdispatchers/qeventdispatcher_cf.mm, line 237
  </code></pre>
  
  <p>In the stack trace I see my <code>waitForFinished()</code> on the main thread, but then instead of being blocked I see (read from bottom up):</p>
  
  <pre><code>com.myapp   0x0008b669 QEventDispatcherCoreFoundation::processEvents(QFlags&lt;QEventLoop::ProcessEventsFlag&gt;) + 1753
  com.myapp   0x000643d7 QIOSEventDispatcher::processEvents(QFlags&lt;QEventLoop::ProcessEventsFlag&gt;) + 823
  com.myapp   0x0130e3c7 QEventLoop::processEvents(QFlags&lt;QEventLoop::ProcessEventsFlag&gt;) + 119
  com.myapp   0x0130e5fb QEventLoop::exec(QFlags&lt;QEventLoop::ProcessEventsFlag&gt;) + 539
  com.myapp   0x0003a550 NetworkFacade::syncGet(QUrl const&amp;) + 208
  com.myapp   0x00037ed1 QtConcurrent::StoredFunctorCall0&lt;std::__1::shared_ptr&lt;QuoteFacade::Quote&gt;, QuoteFacade::closingQuote(QString const&amp;, QDate const&amp;)::$_0&gt;::runFunctor() + 49
  com.myapp   0x00038967 QtConcurrent::RunFunctionTask&lt;std::__1::shared_ptr&lt;QuoteFacade::Quote&gt; &gt;::run() + 87
  com.myapp   0x00038abc non-virtual thunk to QtConcurrent::RunFunctionTask&lt;std::__1::shared_ptr&lt;QuoteFacade::Quote&gt; &gt;::run() + 28
  com.myapp   0x010dc40f QThreadPoolPrivate::stealRunnable(QRunnable*) + 431
  com.myapp   0x010d0c35 QFutureInterfaceBase::waitForFinished() + 165
  </code></pre>
  
  <p>So rather than waiting for the <code>QFuture</code> to get a value, my supposedly concurrent task is issued on the main thread. This causes the <code>get()</code> function I outlined above to get invoked, which listens for events on the <code>QEventLoop</code>. Meanwhile, the <code>QTimer</code> fires again and I get the assertion from above.</p>
  
  <p>Am I doing something wrong, or is it perfectly valid that <code>QtConcurrent::run</code> can cause control to go back to the main thread?</p>
  
  <p>=== Update 1</p>
  
  <p>@peppe: The lambda being executed simply does an HTTP GET and generates parses the JSON response into a <code>SomeType</code> object. The result being accessed via the <code>QFuture</code>.</p>
  
  <p>=== Update 2</p>
  
  <p>Apparently this is by design. From <code>qfutureinterface.cpp</code> from Qt 5.4.0 lines 293-295:</p>
  
  <pre><code>// To avoid deadlocks and reduce the number of threads used, try to
  // run the runnable in the current thread.
  d-&gt;pool()-&gt;d_func()-&gt;stealRunnable(d-&gt;runnable);
  </code></pre>