コード例 #1
0
void tst_QThreadPool::tryStart()
{
    class WaitingTask : public QRunnable
    {
    public:
        QSemaphore semaphore;

        WaitingTask() { setAutoDelete(false); }

        void run()
        {
            semaphore.acquire();
            count.ref();
        }
    };

    count.store(0);

    WaitingTask task;
    QThreadPool threadPool;
    for (int i = 0; i < threadPool.maxThreadCount(); ++i) {
        threadPool.start(&task);
    }
    QVERIFY(!threadPool.tryStart(&task));
    task.semaphore.release(threadPool.maxThreadCount());
    threadPool.waitForDone();
    QCOMPARE(count.load(), threadPool.maxThreadCount());
}
コード例 #2
0
void tst_QThreadPool::destroyingWaitsForTasksToFinish()
{
    QTime total, pass;
    total.start();

    while (total.elapsed() < 10000) {
        int runs;
        count.store(runs = 0);
        {
            QThreadPool threadPool;
            pass.restart();
            while (pass.elapsed() < 100) {
                threadPool.start(new CountingRunnable());
                ++runs;
            }
        }
        QCOMPARE(count.load(), runs);

        count.store(runs = 0);
        {
            QThreadPool threadPool;
            pass.restart();
            while (pass.elapsed() < 100) {
                threadPool.start(new CountingRunnable());
                threadPool.start(new CountingRunnable());
                runs += 2;
            }
        }
        QCOMPARE(count.load(), runs);
    }
}
コード例 #3
0
void TestPointer::multiRef(int count)
{
	QAtomicInt											counter;
	PointerClass									*	ptrClass	=	new PointerClass(counter);
	QList<Pointer<PointerClass> >		ptrList;
	
	QVERIFY(counter.fetchAndAddOrdered(0) == 1);
	
	// Create pointer
	for(int i = 0; i < count; i++)
	{
		ptrList.append(Pointer<PointerClass>(ptrClass));
		
		QVERIFY(ptrList.last() != 0);
		QVERIFY(counter.fetchAndAddOrdered(0) == 1);
		QVERIFY(ptrList.last()->testFunc());
	}
	
	// Remove pointer (all but one)
	for(int i = count - 1; i > 0; i--)
	{
		ptrList.removeLast();
		
		QVERIFY(ptrList.last() != 0);
		QVERIFY(counter.fetchAndAddOrdered(0) == 1);
		QVERIFY(ptrList.last()->testFunc());
	}
	
	Pointer<PointerClass>	ptr(ptrList.takeLast());
	ptr	=	0;
	
	QVERIFY(ptr == 0);
	QVERIFY(counter.fetchAndAddOrdered(0) == 0);
}
コード例 #4
0
ファイル: logging.cpp プロジェクト: StefanRoss/mythtv
static LoggingItem *createItem(
    const char *_file, const char *_function,
    int _line, LogLevel_t _level, int _type)
{
    LoggingItem *item = new LoggingItem(
        _file, _function, _line, _level, _type);

    malloc_count.ref();

#if DEBUG_MEMORY
    int val = item_count.fetchAndAddRelaxed(1) + 1;
    if (val == 0)
        memory_time.start();
    max_count = (val > max_count) ? val : max_count;
    if (memory_time.elapsed() > 1000)
    {
        cout<<"current memory usage: "
            <<val<<" * "<<sizeof(LoggingItem)<<endl;
        cout<<"max memory usage: "
            <<max_count<<" * "<<sizeof(LoggingItem)<<endl;
        cout<<"malloc count: "<<(int)malloc_count<<endl;
        memory_time.start();
    }
#else
    item_count.ref();
#endif

    return item;
}
コード例 #5
0
ファイル: ObjectId.cpp プロジェクト: johnbolia/schat
ObjectId &ObjectId::init()
{
  static QAtomicInt inc = static_cast<unsigned>(QScopedPointer<SecureRandom>(SecureRandom::create())->nextInt64());

  {
    unsigned t = (unsigned) ::time(0);
    uchar *T = (uchar *) &t;
    _time[0] = T[3]; // big endian order because we use memcmp() to compare OID's
    _time[1] = T[2];
    _time[2] = T[1];
    _time[3] = T[0];
  }

  _machineAndPid = ourMachineAndPid;

  {
    const int new_inc = inc.fetchAndAddOrdered(1);
    uchar *T = (uchar *) &new_inc;
    _inc[0] = T[2];
    _inc[1] = T[1];
    _inc[2] = T[0];
  }

  return *this;
}
コード例 #6
0
void tst_QThreadPool::waitForDone()
{
    QTime total, pass;
    total.start();

    QThreadPool threadPool;
    while (total.elapsed() < 10000) {
        int runs;
        count.store(runs = 0);
        pass.restart();
        while (pass.elapsed() < 100) {
            threadPool.start(new CountingRunnable());
            ++runs;
        }
        threadPool.waitForDone();
        QCOMPARE(count.load(), runs);

        count.store(runs = 0);
        pass.restart();
        while (pass.elapsed() < 100) {
            threadPool.start(new CountingRunnable());
            threadPool.start(new CountingRunnable());
            runs += 2;
        }
        threadPool.waitForDone();
        QCOMPARE(count.load(), runs);
    }
}
コード例 #7
0
void TestMallocPrivate::updatePeak()
{
    if (now_usable.load() > peak_usable.load()) {
        peak_usable.fetchAndStoreOrdered(now_usable.load());
    }
    if (now_usable.load() + now_overhead.load() > peak_total.load()) {
        peak_total.fetchAndStoreOrdered(now_usable.load() + now_overhead.load());
    }
}
コード例 #8
0
ファイル: qfbwindow.cpp プロジェクト: KDE/android-qt5-qtbase
QT_BEGIN_NAMESPACE

QFbWindow::QFbWindow(QWindow *window)
    : QPlatformWindow(window), mBackingStore(0)
{
    static QAtomicInt winIdGenerator(1);
    mWindowId = winIdGenerator.fetchAndAddRelaxed(1);

    platformScreen()->addWindow(this);
}
コード例 #9
0
            void run()
            {
                testsTurn.release();

                threadsTurn.acquire();
                QVERIFY(!recursiveMutex.tryLock());
                testsTurn.release();

                threadsTurn.acquire();
                QVERIFY(recursiveMutex.tryLock());
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
                QVERIFY(recursiveMutex.tryLock());
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
                recursiveMutex.unlock();
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
                recursiveMutex.unlock();
                testsTurn.release();

                threadsTurn.acquire();
                QTime timer;
                timer.start();
                QVERIFY(!recursiveMutex.tryLock(waitTime));
                QVERIFY(timer.elapsed() >= waitTime);
                QVERIFY(!recursiveMutex.tryLock(0));
                testsTurn.release();

                threadsTurn.acquire();
                timer.start();
                QVERIFY(recursiveMutex.tryLock(waitTime));
                QVERIFY(timer.elapsed() <= waitTime);
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
                QVERIFY(recursiveMutex.tryLock(waitTime));
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
                recursiveMutex.unlock();
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
                recursiveMutex.unlock();
                testsTurn.release();

                threadsTurn.acquire();
                QVERIFY(!recursiveMutex.tryLock(0));
                QVERIFY(!recursiveMutex.tryLock(0));
                testsTurn.release();

                threadsTurn.acquire();
                timer.start();
                QVERIFY(recursiveMutex.tryLock(0));
                QVERIFY(timer.elapsed() < waitTime);
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
                QVERIFY(recursiveMutex.tryLock(0));
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
                recursiveMutex.unlock();
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
                recursiveMutex.unlock();
                testsTurn.release();

                threadsTurn.acquire();
            }
コード例 #10
0
void CallbackObject::Run(void)
{
    // start the run loop
    if (gAdminRunLoopRunning.fetchAndAddOrdered(0))
        CFRunLoopRun();

    // if it exits, schedule it to start again. This usually means there is nothing
    // setup using a callback, so don't waste cycles and wait a while before restarting.
    if (gAdminRunLoopRunning.fetchAndAddOrdered(0))
        QTimer::singleShot(100, Qt::CoarseTimer, this, SLOT(Run()));
}
コード例 #11
0
void tst_QtConcurrentIterateKernel::stresstest()
{
    const int iterations = 1000;
    const int times = 50;
    for (int i = 0; i < times; ++i) {
        counter.store(0);
        CountFor f(0, iterations);
        f.startBlocking();
        QCOMPARE(counter.load(), iterations);
    }
}
コード例 #12
0
void tst_QThreadPool::start()
{
    const int runs = 1000;
    count.store(0);
    {
        QThreadPool threadPool;
        for (int i = 0; i< runs; ++i) {
            threadPool.start(new CountingRunnable());
        }
    }
    QCOMPARE(count.load(), runs);
}
コード例 #13
0
void tst_QtConcurrentIterateKernel::cancel()
{
    {
        QFuture<void> f = startThreadEngine(new SleepPrintFor(0, 40)).startAsynchronously();
        f.cancel();
        f.waitForFinished();
        QVERIFY(f.isCanceled());
         // the threads might run one iteration each before they are canceled.
        QVERIFY2(iterations.load() <= QThread::idealThreadCount(),
                 (QByteArray::number(iterations.load()) + ' ' + QByteArray::number(QThread::idealThreadCount())));
    }
}
コード例 #14
0
void TestPointer::single()
{
	QAtomicInt							counter;
	Pointer<PointerClass>		ptr(new PointerClass(counter));
	
	QVERIFY(ptr != 0);
	QVERIFY(counter.fetchAndAddOrdered(0) == 1);
	QVERIFY(ptr->testFunc());
	
	ptr	=	0;
	
	QVERIFY(ptr == 0);
	QVERIFY(counter.fetchAndAddOrdered(0) == 0);
}
コード例 #15
0
ファイル: loggingserver.cpp プロジェクト: bas-t/mythtv
/// \brief Expire any clients in the delete list
void LogForwardThread::expireClients(void)
{
#ifndef NOLOGSERVER
    QMutexLocker lock(&logClientMapMutex);
    QMutexLocker lock2(&logRevClientMapMutex);
    QMutexLocker lock3(&logClientToDelMutex);

    while (!logClientToDel.isEmpty())
    {
        QString clientId = logClientToDel.takeFirst();
        logClientCount.deref();
        LOG(VB_GENERAL, LOG_INFO, QString("Expiring client %1 (#%2)")
            .arg(clientId).arg(logClientCount.fetchAndAddOrdered(0)));
        LoggerListItem *item = logClientMap.take(clientId);
        if (!item)
            continue;
        LoggerList *list = item->list;
        delete item;

        while (!list->isEmpty())
        {
            LoggerBase *logger = list->takeFirst();
            ClientList *clientList = logRevClientMap.value(logger, NULL);
            if (!clientList || clientList->size() == 1)
            {
                if (clientList)
                {
                    logRevClientMap.remove(logger);
                    delete clientList;
                }
                delete logger;
                continue;
            }

            clientList->removeAll(clientId);
        }
        delete list;
    }

    // TODO FIXME: This is not thread-safe!
    // just this daemon left
    if (logClientCount.fetchAndAddOrdered(0) == 1 &&
        m_shutdownTimer && !m_shutdownTimer->isActive())
    {
        LOG(VB_GENERAL, LOG_INFO, "Starting 5min shutdown timer");
        m_shutdownTimer->start(5*60*1000);
    }
#endif
}
コード例 #16
0
// Test that a user task with a thread function that always
// want to be throttled still completes. The thread engine
// should make keep one thread running at all times.
void tst_QtConcurrentThreadEngine::throttle()
{
    const int repeats = 10;
    for (int i = 0; i < repeats; ++i) {
        QFuture<void> f = (new ThrottleAlwaysUser())->startAsynchronously();
        f.waitForFinished();
        QCOMPARE(count.load(), 0);
    }

    for (int i = 0; i < repeats; ++i) {
        ThrottleAlwaysUser t;
        t.startBlocking();
        QCOMPARE(count.load(), 0);
    }
}
コード例 #17
0
void tst_QtConcurrentIterateKernel::throttling()
{
    const int totalIterations = 400;
    iterations.store(0);

    threads.clear();

    ThrottleFor f(0, totalIterations);
    f.startBlocking();

    QCOMPARE(iterations.load(), totalIterations);


    QCOMPARE(threads.count(), 1);
}
コード例 #18
0
TActionWorker::TActionWorker(TEpollSocket *socket, QObject *parent)
    : QThread(parent), TActionContext(), httpRequest(), clientAddr(), socketId(socket->id())
{
    workerCounter.fetchAndAddOrdered(1);
    httpRequest = socket->recvBuffer().read(INT_MAX);
    clientAddr = socket->recvBuffer().clientAddress().toString();
}
コード例 #19
0
ファイル: Drive.cpp プロジェクト: toxa-svr/ServoDrive
// slots
void Drive::update()
{
    if (!isOpened)
        return;
    PdoData pdoData;
    memcpy(&pdoData, ec_slave[1].inputs, sizeof(pdoData));
    //qDebug() << "statusword: " << pdoData.statusword;
    //qDebug() << "velocity actual value: " << pdoData.velocityActualValue;
    //qDebug() << "measurement velocity rpm: " << pdoData.measurementVelRpm;
    //qDebug() << "current actual filtered value: " << pdoData.currentActualValue;
    //qDebug() << "ue: " << pdoData.ue;
    //qDebug() << "up: " << pdoData.up;

    emit rpmChanged(pdoData.velocityActualValue);
    //emit currentChanged(pdoData.currentActualValue);

    bool ok = !EcatError;
    while (EcatError)
        qDebug("%s", ec_elist2string());

    //emit stateChanged(ok);
    ok = true;
//
//    qDebug("Slave State=0x%2.2x StatusCode=0x%4.4x : %s",
//           ec_slave[1].state, ec_slave[1].ALstatuscode, ec_ALstatuscode2string(ec_slave[1].ALstatuscode));

    if (globalErrorFlag.fetchAndStoreRelaxed(GLOBAL_OK) == GLOBAL_ERROR) {
        qDebug("ERROR from iothread");
        isWorking = false;
        emit error();
    }
}
コード例 #20
0
ファイル: Thread.hpp プロジェクト: adolby/Kryvos
   /// Take an object and prevent timer resource leaks when the object is about
   /// to become threadless.
   void takeObject(QObject *obj) {
      // Work around to prevent
      // QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
      static constexpr char kRegistered[] = "__ThreadRegistered";
      static constexpr char kMoved[] = "__Moved";
      if (!obj->property(kRegistered).isValid()) {
         QObject::connect(this, &Thread::finished, obj, [this, obj]{
            if (!inDestructor.load() || obj->thread() != this)
               return;
            // The object is about to become threadless
            Q_ASSERT(obj->thread() == QThread::currentThread());
            obj->setProperty(kMoved, true);
            obj->moveToThread(this->thread());
         }, Qt::DirectConnection);
         QObject::connect(this, &QObject::destroyed, obj, [obj]{
            if (!obj->thread()) {
               obj->moveToThread(QThread::currentThread());
               obj->setProperty(kRegistered, {});
            }
            else if (obj->thread() == QThread::currentThread() && obj->property(kMoved).isValid()) {
               obj->setProperty(kMoved, {});
               QCoreApplication::sendPostedEvents(obj, QEvent::MetaCall);
            }
            else if (obj->thread()->eventDispatcher())
               QTimer::singleShot(0, obj, [obj]{ obj->setProperty(kRegistered, {}); });
         }, Qt::DirectConnection);

         obj->setProperty(kRegistered, true);
      }
      obj->moveToThread(this);
   }
コード例 #21
0
ULONG		CDeckLinkGLWidget::AddRef ()
{
	int		oldValue;
	
	oldValue = refCount.fetchAndAddAcquire(1);
	return (ULONG)(oldValue + 1);
}
コード例 #22
0
/**
 * Network streaming request
 */
NetStream::NetStream(const QUrl &url, EMode mode /*= kPreferCache*/) :
    m_id(s_nRequest.fetchAndAddRelaxed(1)),
    m_state(kClosed),
    m_pending(0),
    m_reply(0),
    m_nRedirections(0),
    m_size(-1),
    m_pos(0)
{
    setObjectName("NetStream " + url.toString());

    m_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
        mode == kAlwaysCache ? QNetworkRequest::AlwaysCache :
        mode == kPreferCache ? QNetworkRequest::PreferCache :
        mode == kNeverCache ? QNetworkRequest::AlwaysNetwork :
            QNetworkRequest::PreferNetwork );

    // Receive requestStarted signals from NAMThread when it processes a NetStreamRequest
    connect(&NAMThread::manager(), SIGNAL(requestStarted(int, QNetworkReply*)),
        this, SLOT(slotRequestStarted(int, QNetworkReply*)), Qt::DirectConnection );

    QMutexLocker locker(&m_mutex);

    if (Request(url))
        m_state = kPending;
}
コード例 #23
0
void MfSession::setup()
{
    if (!setupInProgress.testAndSetAcquire(0, 1)) {
        // If a session setup is in progress wait some time
        QTimer::singleShot(10, this, SLOT(setup()));
        return;
    }

    MfManager *manager = MfManager::instance();
    QVector<QStringList> feedbackDirLists = getFeedbackDirLists(manager->currentTheme(), appName);
    QStringList feedbackDirs;

    for (int i = 0; i < feedbackDirLists.size(); ++i) {
        feedbackDirs << feedbackDirLists[i][0];
    }

    if (feedbackDirLists.isEmpty()) {
        // Can't live without feedbacks
        qFatal("It is not possible to load any feedbacks.");
    }

    // Map the feedbacks
    foreach (const QStringList& feedbackDirList, feedbackDirLists) {
        MfFeedback *feedback = new MfFeedback(this);
        feedback->load(feedbackDirList);
        feedbackHash[feedback->name()] = feedback;
    }
コード例 #24
0
ファイル: qhostinfo.cpp プロジェクト: fluxer/katie
/*!
    Looks up the IP address(es) associated with host name \a name, and
    returns an ID for the lookup. When the result of the lookup is
    ready, the slot or signal \a member in \a receiver is called with
    a QHostInfo argument. The QHostInfo object can then be inspected
    to get the results of the lookup.

    The lookup is performed by a single function call, for example:

    \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 2

    The implementation of the slot prints basic information about the
    addresses returned by the lookup, or reports an error if it failed:

    \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 3

    If you pass a literal IP address to \a name instead of a host name,
    QHostInfo will search for the domain name for the IP (i.e., QHostInfo will
    perform a \e reverse lookup). On success, the resulting QHostInfo will
    contain both the resolved domain name and IP addresses for the host
    name. Example:

    \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4

    \note There is no guarantee on the order the signals will be emitted
    if you start multiple requests with lookupHost().

    \sa abortHostLookup(), addresses(), error(), fromName()
*/
int QHostInfo::lookupHost(const QString &name, QObject *receiver,
                          const char *member)
{
#if defined QHOSTINFO_DEBUG
    qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)",
           name.toLatin1().constData(), receiver, member ? member + 1 : 0);
#endif

    if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
        qWarning("QHostInfo::lookupHost() called with no event dispatcher");
        return -1;
    }

    qRegisterMetaType<QHostInfo>("QHostInfo");

    int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID

    if (name.isEmpty()) {
        if (!receiver)
            return -1;

        QHostInfo hostInfo(id);
        hostInfo.setError(QHostInfo::HostNotFound);
        hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
        QScopedPointer<QHostInfoResult> result(new QHostInfoResult);
        QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)),
                         receiver, member, Qt::QueuedConnection);
        result.data()->emitResultsReady(hostInfo);
        return id;
    }

    QHostInfoLookupManager *manager = theHostInfoLookupManager();

    if (manager) {
        // the application is still alive
        if (manager->cache.isEnabled()) {
            // check cache first
            bool valid = false;
            QHostInfo info = manager->cache.get(name, &valid);
            if (valid) {
                if (!receiver)
                    return -1;

                info.setLookupId(id);
                QHostInfoResult result;
                QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
                result.emitResultsReady(info);
                return id;
            }
        }

        // cache is not enabled or it was not in the cache, do normal lookup
        QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id);
        if (receiver)
            QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection);
        manager->scheduleLookup(runnable);
    }

    return id;
}
コード例 #25
0
int TActionThread::threadCount()
{
#if QT_VERSION >= 0x050000
    return threadCounter.load();
#else
    return (int)threadCounter;
#endif
}
コード例 #26
0
    bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *)
    {
        iterations.fetchAndAddRelaxed(end - begin);
#ifdef PRINT
        qDebug() << QThread::currentThread() << "iteration" << begin <<  "to" << end << "(exclusive)";
#endif
        return false;
    }
コード例 #27
0
int TActionWorker::workerCount()
{
#if QT_VERSION >= 0x050000
    return workerCounter.load();
#else
    return (int)workerCounter;
#endif
}
コード例 #28
0
 void run()
 {
     testRwlock.lockForWrite();
     while(release.load()==false) {
         RWTESTSLEEP
     }
     testRwlock.unlock();
 }
コード例 #29
0
toConnectionSub *toQPSqlConnectionImpl::createConnection(void)
{
    // TODO shouldn't be this method reenteant?
    static QAtomicInt ID_COUNTER(0);
    int ID = ID_COUNTER.fetchAndAddAcquire(1);

    QString dbName = QString::number(ID);
    QSqlDatabase db = QSqlDatabase::addDatabase(parentConnection().provider(), dbName);
    db.setDatabaseName(parentConnection().database());
    QString host = parentConnection().host();
    int pos = host.indexOf(QString(":"));
    if (pos < 0)
        db.setHostName(host);
    else
    {
        db.setHostName(host.mid(0, pos));
        db.setPort(host.mid(pos + 1).toInt());
    }

    QString opt;

    QSet<QString> options = parentConnection().options();
    if (options.find("Compress") != options.end())
        opt += ";CLIENT_COMPRESS";
    if (options.find("Ignore Space") != options.end())
        opt += ";CLIENT_IGNORE_SPACE";
    if (options.find("No Schema") != options.end())
        opt += ";CLIENT_NO_SCHEMA";
    if (options.find("SSL") != options.end())
        opt += ";CLIENT_SSL";

    if (!opt.isEmpty())
        db.setConnectOptions(opt.mid(1)); // Strip first ; character

    db.open(parentConnection().user(), parentConnection().password());
    if (!db.isOpen())
    {
        QString t = toQPSqlConnectionSub::ErrorString(db.lastError());
        QSqlDatabase::removeDatabase(dbName);
        throw t;
    }

    toQPSqlConnectionSub *ret = new toQPSqlConnectionSub(parentConnection(), db, dbName);
    return ret;
}
コード例 #30
0
void tst_QtConcurrentRun::recursive()
{
    int levels = 15;

    for (int i = 0; i < QThread::idealThreadCount(); ++i) {
        count.store(0);
        QThreadPool::globalInstance()->setMaxThreadCount(i);
        recursiveRun(levels);
        QCOMPARE(count.load(), (int)pow(2.0, levels) - 1);
    }

    for (int i = 0; i < QThread::idealThreadCount(); ++i) {
        count.store(0);
        QThreadPool::globalInstance()->setMaxThreadCount(i);
        recursiveResult(levels);
        QCOMPARE(count.load(), (int)pow(2.0, levels) - 1);
    }
}