AutoSem(QSemaphore* sem) : s(sem) { s->release();}
void GenerateMultipleThread::run() { genMulti.abortOptimization=false; time(&initial_time); for(int i=0; i<nTimetables; i++){ time(&start_time); bool impossible; bool timeExceeded; for(int qq=0; qq<gt.rules.nInternalActivities; qq++) permutation[qq]=savedPermutation[qq]; emit(timetableStarted(i+1)); semaphoreTimetableStarted.acquire(); genMulti.generate(timeLimit, impossible, timeExceeded, true); //true means threaded QString s; bool ok; myMutex.lock(); if(genMulti.abortOptimization){ myMutex.unlock(); return; } else if(impossible){ s=tr("Timetable impossible to generate"); s+=QString("."); ok=false; } else if(timeExceeded){ s=tr("Time exceeded for current timetable"); ////////2011-05-26 int mact=maxActivitiesPlaced; int mseconds=genMulti.timeToHighestStage; bool zero=false; if(mseconds==0) zero=true; int hh=mseconds/3600; mseconds%=3600; int mm=mseconds/60; mseconds%=60; int ss=mseconds; QString tim; if(hh>0){ tim+=" "; tim+=tr("%1 h", "hours").arg(hh); } if(mm>0){ tim+=" "; tim+=tr("%1 m", "minutes").arg(mm); } if(ss>0 || zero){ tim+=" "; tim+=tr("%1 s", "seconds").arg(ss); } tim.remove(0, 1); s+=QString(". "); s+=tr("Max placed activities: %1 (at %2)", "%1 represents the maximum number of activities placed, %2 is a time interval").arg(mact).arg(tim); /////// s+=QString("."); ok=false; } else{ ok=true; time_t finish_time; time(&finish_time); int seconds=int(finish_time-start_time); int hours=seconds/3600; seconds%=3600; int minutes=seconds/60; seconds%=60; QString tmp; genMulti.c.fitness(gt.rules, &tmp); s=tr("Timetable has %1 soft conflicts factor and was generated in %2 hours, %3 minutes and %4 seconds") .arg(CustomFETString::number(genMulti.c.conflictsTotal)) .arg(hours) .arg(minutes) .arg(seconds); s+=QString("."); } myMutex.unlock(); emit(timetableGenerated(i+1, s, ok)); semaphoreTimetableFinished.acquire(); } emit(finished()); }
void waitForTest() { semaphore.release(); testSemaphore.acquire(); }
void tst_QSemaphore::tryAcquireWithTimeout() { QFETCH(int, timeout); QSemaphore semaphore; QTime time; QCOMPARE(semaphore.available(), 0); semaphore.release(); QCOMPARE(semaphore.available(), 1); time.start(); QVERIFY(!semaphore.tryAcquire(2, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 1); semaphore.release(); QCOMPARE(semaphore.available(), 2); time.start(); QVERIFY(!semaphore.tryAcquire(3, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 2); semaphore.release(10); QCOMPARE(semaphore.available(), 12); time.start(); QVERIFY(!semaphore.tryAcquire(100, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 12); semaphore.release(10); QCOMPARE(semaphore.available(), 22); time.start(); QVERIFY(!semaphore.tryAcquire(100, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 22); time.start(); QVERIFY(semaphore.tryAcquire(1, timeout)); QVERIFY(time.elapsed() <= timeout); QCOMPARE(semaphore.available(), 21); time.start(); QVERIFY(semaphore.tryAcquire(1, timeout)); QVERIFY(time.elapsed() <= timeout); QCOMPARE(semaphore.available(), 20); time.start(); QVERIFY(semaphore.tryAcquire(10, timeout)); QVERIFY(time.elapsed() <= timeout); QCOMPARE(semaphore.available(), 10); time.start(); QVERIFY(semaphore.tryAcquire(10, timeout)); QVERIFY(time.elapsed() <= timeout); QCOMPARE(semaphore.available(), 0); // should not be able to acquire more time.start(); QVERIFY(!semaphore.tryAcquire(1, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(1, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(10, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 0); time.start(); QVERIFY(!semaphore.tryAcquire(10, timeout)); QVERIFY(time.elapsed() >= timeout); QCOMPARE(semaphore.available(), 0); }
void TimetableGenerateMultipleForm::timetableStarted(int timetable) { TimetableExport::writeRandomSeed(this, timetable, true); //true represents 'before' state semaphoreTimetableStarted.release(); }
void TimetableGenerateForm::simulationFinished() { if(!simulation_running){ return; } simulation_running=false; finishedSemaphore.acquire(); TimetableExport::writeRandomSeed(this, false); //false represents 'before' state Solution& c=gen.c; //needed to find the conflicts strings QString tmp; c.fitness(gt.rules, &tmp); TimetableExport::getStudentsTimetable(c); TimetableExport::getTeachersTimetable(c); TimetableExport::getRoomsTimetable(c); //update the string representing the conflicts conflictsStringTitle=TimetableGenerateForm::tr("Soft conflicts", "Title of dialog"); conflictsString=""; conflictsString+=tr("Total soft conflicts:"); conflictsString+=" "; conflictsString+=CustomFETString::number(c.conflictsTotal); conflictsString+="\n"; conflictsString+=TimetableGenerateForm::tr("Soft conflicts listing (in decreasing order):"); conflictsString+="\n"; foreach(QString t, c.conflictsDescriptionList) conflictsString+=t+"\n"; TimetableExport::writeSimulationResults(this); QString kk; kk=FILE_SEP; if(INPUT_FILENAME_XML=="") kk.append("unnamed"); else{ kk.append(INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1)); if(kk.right(4)==".fet") kk=kk.left(kk.length()-4); } kk.append("-single"); /* QMessageBox::information(this, TimetableGenerateForm::tr("FET information"), TimetableGenerateForm::tr("Allocation terminated successfully, remaining %1 weighted" " soft conflicts from constraints with weight percentage lower than 100%" " (see menu Timetable/Show soft conflicts or the text file in" " the output directory for details)." "\n\nSimulation results should be now written. You may check now Timetable/View." " The results are also saved in the directory %2 in" " html and xml mode and the soft conflicts in txt mode").arg(c.conflictsTotal).arg(QDir::toNativeSeparators(OUTPUT_DIR+FILE_SEP+"timetables"+kk)) +". "+tr("Data+timetable is saved as a .fet data file (with activities locked by constraints)" ", so that you can open/modify/regenerate the current timetable later")); */ QString s=QString(""); s+=tr("Generation successful!"); s+=QString("\n\n"); s+=tr("Weighted soft conflicts: %1").arg(CustomFETString::number(c.conflictsTotal)); s+=QString("\n\n"); s+=tr("Results were saved in the directory %1").arg(QDir::toNativeSeparators(OUTPUT_DIR+FILE_SEP+"timetables"+kk)); QMessageBox::information(this, TimetableGenerateForm::tr("FET information"), s); startPushButton->setEnabled(true); stopPushButton->setDisabled(true); stopHighestPushButton->setDisabled(true); closePushButton->setEnabled(true); writeResultsPushButton->setDisabled(true); writeHighestStagePushButton->setDisabled(true); seeImpossiblePushButton->setDisabled(true); }
void run() { recycledThread = QThread::currentThread(); threadRecyclingSemaphore.release(); }
void tst_QReadWriteLock::tryReadLock() { QReadWriteLock rwlock; QVERIFY(rwlock.tryLockForRead()); rwlock.unlock(); QVERIFY(rwlock.tryLockForRead()); rwlock.unlock(); rwlock.lockForRead(); rwlock.lockForRead(); QVERIFY(rwlock.tryLockForRead()); rwlock.unlock(); rwlock.unlock(); rwlock.unlock(); rwlock.lockForWrite(); QVERIFY(!rwlock.tryLockForRead()); rwlock.unlock(); // functionality test { class Thread : public QThread { public: void run() { testsTurn.release(); threadsTurn.acquire(); QVERIFY(!readWriteLock.tryLockForRead()); testsTurn.release(); threadsTurn.acquire(); QVERIFY(readWriteLock.tryLockForRead()); lockCount.ref(); QVERIFY(readWriteLock.tryLockForRead()); lockCount.ref(); lockCount.deref(); readWriteLock.unlock(); lockCount.deref(); readWriteLock.unlock(); testsTurn.release(); threadsTurn.acquire(); QTime timer; timer.start(); QVERIFY(!readWriteLock.tryLockForRead(1000)); QVERIFY(timer.elapsed() >= 1000); testsTurn.release(); threadsTurn.acquire(); timer.start(); QVERIFY(readWriteLock.tryLockForRead(1000)); QVERIFY(timer.elapsed() <= 1000); lockCount.ref(); QVERIFY(readWriteLock.tryLockForRead(1000)); lockCount.ref(); lockCount.deref(); readWriteLock.unlock(); lockCount.deref(); readWriteLock.unlock(); testsTurn.release(); threadsTurn.acquire(); } }; Thread thread; thread.start(); testsTurn.acquire(); readWriteLock.lockForWrite(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); readWriteLock.unlock(); threadsTurn.release(); testsTurn.acquire(); readWriteLock.lockForWrite(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); readWriteLock.unlock(); threadsTurn.release(); // stop thread testsTurn.acquire(); threadsTurn.release(); thread.wait(); } }
void tst_QReadWriteLock::tryWriteLock() { { QReadWriteLock rwlock; QVERIFY(rwlock.tryLockForWrite()); rwlock.unlock(); QVERIFY(rwlock.tryLockForWrite()); rwlock.unlock(); rwlock.lockForWrite(); QVERIFY(!rwlock.tryLockForWrite()); QVERIFY(!rwlock.tryLockForWrite()); rwlock.unlock(); rwlock.lockForRead(); QVERIFY(!rwlock.tryLockForWrite()); rwlock.unlock(); } { QReadWriteLock rwlock(QReadWriteLock::Recursive); QVERIFY(rwlock.tryLockForWrite()); rwlock.unlock(); QVERIFY(rwlock.tryLockForWrite()); rwlock.unlock(); rwlock.lockForWrite(); QVERIFY(rwlock.tryLockForWrite()); QVERIFY(rwlock.tryLockForWrite()); rwlock.unlock(); rwlock.unlock(); rwlock.unlock(); rwlock.lockForRead(); QVERIFY(!rwlock.tryLockForWrite()); rwlock.unlock(); } // functionality test { class Thread : public QThread { public: Thread() : failureCount(0) { } void run() { testsTurn.release(); threadsTurn.acquire(); if (readWriteLock.tryLockForWrite()) failureCount++; testsTurn.release(); threadsTurn.acquire(); if (!readWriteLock.tryLockForWrite()) failureCount++; if (!lockCount.testAndSetRelaxed(0, 1)) failureCount++; if (!lockCount.testAndSetRelaxed(1, 0)) failureCount++; readWriteLock.unlock(); testsTurn.release(); threadsTurn.acquire(); if (readWriteLock.tryLockForWrite(1000)) failureCount++; testsTurn.release(); threadsTurn.acquire(); if (!readWriteLock.tryLockForWrite(1000)) failureCount++; if (!lockCount.testAndSetRelaxed(0, 1)) failureCount++; if (!lockCount.testAndSetRelaxed(1, 0)) failureCount++; readWriteLock.unlock(); testsTurn.release(); threadsTurn.acquire(); } int failureCount; }; Thread thread; thread.start(); testsTurn.acquire(); readWriteLock.lockForRead(); lockCount.ref(); threadsTurn.release(); testsTurn.acquire(); lockCount.deref(); readWriteLock.unlock(); threadsTurn.release(); testsTurn.acquire(); readWriteLock.lockForRead(); lockCount.ref(); threadsTurn.release(); testsTurn.acquire(); lockCount.deref(); readWriteLock.unlock(); threadsTurn.release(); // stop thread testsTurn.acquire(); threadsTurn.release(); thread.wait(); QCOMPARE(thread.failureCount, 0); } }
void wait() { semaphore.acquire(); }
void run() { semaphore.release(); }
void run() { semaphore.acquire(); count.ref(); }
void run() { waitForStarted.release(); waitToFinish.acquire(); }
void run() { thread = QThread::currentThread(); ++runCount; semaphore.release(); }
~AutoSem() { if (s->available() > 0) s->acquire(s->available()); }
void tst_QSemaphore::acquire() { { // old incrementOne() test QVERIFY(!semaphore); semaphore = new QSemaphore; // make some "thing" available semaphore->release(); ThreadOne t1; ThreadOne t2; t1.start(); t2.start(); QVERIFY(t1.wait(4000)); QVERIFY(t2.wait(4000)); delete semaphore; semaphore = 0; } // old incrementN() test { QVERIFY(!semaphore); semaphore = new QSemaphore; // make 4 "things" available semaphore->release(4); ThreadN t1(2); ThreadN t2(3); t1.start(); t2.start(); QVERIFY(t1.wait(4000)); QVERIFY(t2.wait(4000)); delete semaphore; semaphore = 0; } QSemaphore semaphore; QCOMPARE(semaphore.available(), 0); semaphore.release(); QCOMPARE(semaphore.available(), 1); semaphore.release(); QCOMPARE(semaphore.available(), 2); semaphore.release(10); QCOMPARE(semaphore.available(), 12); semaphore.release(10); QCOMPARE(semaphore.available(), 22); semaphore.acquire(); QCOMPARE(semaphore.available(), 21); semaphore.acquire(); QCOMPARE(semaphore.available(), 20); semaphore.acquire(10); QCOMPARE(semaphore.available(), 10); semaphore.acquire(10); QCOMPARE(semaphore.available(), 0); }
void tst_QMutex::tryLock() { // test non-recursive mutex { class Thread : public QThread { public: void run() { testsTurn.release(); threadsTurn.acquire(); QVERIFY(!normalMutex.tryLock()); testsTurn.release(); threadsTurn.acquire(); QVERIFY(normalMutex.tryLock()); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(!normalMutex.tryLock()); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); testsTurn.release(); threadsTurn.acquire(); QTime timer; timer.start(); QVERIFY(!normalMutex.tryLock(1000)); QVERIFY(timer.elapsed() >= 1000); testsTurn.release(); threadsTurn.acquire(); timer.start(); QVERIFY(normalMutex.tryLock(1000)); QVERIFY(timer.elapsed() <= 1000); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); timer.start(); QVERIFY(!normalMutex.tryLock(1000)); QVERIFY(timer.elapsed() >= 1000); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); testsTurn.release(); threadsTurn.acquire(); } }; Thread thread; thread.start(); testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); threadsTurn.release(); testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); threadsTurn.release(); // wait for thread to finish testsTurn.acquire(); threadsTurn.release(); thread.wait(); } // test recursive mutex { class Thread : public QThread { public: 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(1000)); QVERIFY(timer.elapsed() >= 1000); testsTurn.release(); threadsTurn.acquire(); timer.start(); QVERIFY(recursiveMutex.tryLock(1000)); QVERIFY(timer.elapsed() <= 1000); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(recursiveMutex.tryLock(1000)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); recursiveMutex.unlock(); testsTurn.release(); threadsTurn.acquire(); } }; Thread thread; thread.start(); testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); recursiveMutex.unlock(); threadsTurn.release(); testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); recursiveMutex.unlock(); threadsTurn.release(); // stop thread testsTurn.acquire(); threadsTurn.release(); thread.wait(); } }
void tst_QSemaphore::tryAcquire() { QSemaphore semaphore; QCOMPARE(semaphore.available(), 0); semaphore.release(); QCOMPARE(semaphore.available(), 1); QVERIFY(!semaphore.tryAcquire(2)); QCOMPARE(semaphore.available(), 1); semaphore.release(); QCOMPARE(semaphore.available(), 2); QVERIFY(!semaphore.tryAcquire(3)); QCOMPARE(semaphore.available(), 2); semaphore.release(10); QCOMPARE(semaphore.available(), 12); QVERIFY(!semaphore.tryAcquire(100)); QCOMPARE(semaphore.available(), 12); semaphore.release(10); QCOMPARE(semaphore.available(), 22); QVERIFY(!semaphore.tryAcquire(100)); QCOMPARE(semaphore.available(), 22); QVERIFY(semaphore.tryAcquire()); QCOMPARE(semaphore.available(), 21); QVERIFY(semaphore.tryAcquire()); QCOMPARE(semaphore.available(), 20); QVERIFY(semaphore.tryAcquire(10)); QCOMPARE(semaphore.available(), 10); QVERIFY(semaphore.tryAcquire(10)); QCOMPARE(semaphore.available(), 0); // should not be able to acquire more QVERIFY(!semaphore.tryAcquire()); QCOMPARE(semaphore.available(), 0); QVERIFY(!semaphore.tryAcquire()); QCOMPARE(semaphore.available(), 0); QVERIFY(!semaphore.tryAcquire(10)); QCOMPARE(semaphore.available(), 0); QVERIFY(!semaphore.tryAcquire(10)); QCOMPARE(semaphore.available(), 0); }
void TimetableGenerateForm::activityPlaced(int na){ assert(gt.rules.initialized && gt.rules.internalStructureComputed); myMutex.lock(); int t=gen.searchTime; //seconds int mact=maxActivitiesPlaced; int seconds=gen.timeToHighestStage; myMutex.unlock(); //write to the Qt interface QString s; s+=TimetableGenerateForm::tr("%1 out of %2 activities placed").arg(na).arg(gt.rules.nInternalActivities)+"\n"; s+=TimetableGenerateForm::tr("Elapsed time:"); int h=t/3600; if(h>0){ s+=" "; s+=TimetableGenerateForm::tr("%1 h", "hours").arg(h); } t=t%3600; int m=t/60; if(m>0){ s+=" "; s+=TimetableGenerateForm::tr("%1 m", "minutes").arg(m); } t=t%60; if(t>0){ s+=" "; s+=TimetableGenerateForm::tr("%1 s", "seconds").arg(t); } bool zero=false; if(seconds==0) zero=true; int hh=seconds/3600; seconds%=3600; int mm=seconds/60; seconds%=60; int ss=seconds; QString tim; if(hh>0){ tim+=" "; tim+=tr("%1 h", "hours").arg(hh); } if(mm>0){ tim+=" "; tim+=tr("%1 m", "minutes").arg(mm); } if(ss>0 || zero){ tim+=" "; tim+=tr("%1 s", "seconds").arg(ss); } tim.remove(0, 1); s+="\n\n"; s+=tr("Max placed activities: %1 (at %2)", "%1 represents the maximum number of activities placed, %2 is a time interval").arg(mact).arg(tim); currentResultsTextEdit->setPlainText(s); semaphorePlacedActivity.release(); }
void SearchOperation::doSearch( SearchData& searchData, LineNumber initialLine ) { const auto& config = Persistable::get<Configuration>(); const auto nbSourceLines = sourceLogData_->getNbLine(); LineLength maxLength = 0_length; LinesCount nbMatches = searchData.getNbMatches(); const auto nbLinesInChunk = LinesCount( config.searchReadBufferSizeLines() ); LOG( logDEBUG ) << "Searching from line " << initialLine << " to " << nbSourceLines; if ( initialLine < startLine_ ) { initialLine = startLine_; } const auto endLine = qMin( LineNumber( nbSourceLines.get() ), endLine_ ); using namespace std::chrono; high_resolution_clock::time_point t1 = high_resolution_clock::now(); QSemaphore searchCompleted; QSemaphore blocksDone; using SearchBlockQueue = moodycamel::BlockingConcurrentQueue<SearchBlockData>; using ProcessMatchQueue = moodycamel::BlockingConcurrentQueue<PartialSearchResults>; SearchBlockQueue searchBlockQueue; ProcessMatchQueue processMatchQueue; std::vector<QFuture<void>> matchers; const auto matchingThreadsCount = [&config]() { if ( !config.useParallelSearch() ) { return 1; } return qMax( 1, config.searchThreadPoolSize() == 0 ? QThread::idealThreadCount() - 1 : static_cast<int>( config.searchThreadPoolSize() ) ); }(); LOG( logINFO ) << "Using " << matchingThreadsCount << " matching threads"; auto localThreadPool = std::make_unique<QThreadPool>(); localThreadPool->setMaxThreadCount( matchingThreadsCount + 2 ); const auto makeMatcher = [this, &searchBlockQueue, &processMatchQueue, pool = localThreadPool.get()]( size_t index ) { // copy and optimize regex for each thread auto regexp = QRegularExpression{ regexp_.pattern(), regexp_.patternOptions() }; regexp.optimize(); return QtConcurrent::run( pool, [regexp, index, &searchBlockQueue, &processMatchQueue]() { auto cToken = moodycamel::ConsumerToken{ searchBlockQueue }; auto pToken = moodycamel::ProducerToken{ processMatchQueue }; for ( ;; ) { SearchBlockData blockData; searchBlockQueue.wait_dequeue( cToken, blockData ); LOG( logDEBUG ) << "Searcher " << index << " " << blockData.chunkStart; const auto lastBlock = blockData.lines.empty(); if ( !lastBlock ) { blockData.results = filterLines( regexp, blockData.lines, blockData.chunkStart ); } LOG( logDEBUG ) << "Searcher " << index << " sending matches " << blockData.results.matchingLines.size(); processMatchQueue.enqueue( pToken, std::move( blockData.results ) ); if ( lastBlock ) { LOG( logDEBUG ) << "Searcher " << index << " last block"; return; } } } ); }; for ( int i = 0; i < matchingThreadsCount; ++i ) { matchers.emplace_back( makeMatcher( i ) ); } auto processMatches = QtConcurrent::run( localThreadPool.get(), [&]() { auto cToken = moodycamel::ConsumerToken{ processMatchQueue }; size_t matchersDone = 0; int reportedPercentage = 0; auto reportedMatches = nbMatches; LinesCount totalProcessedLines = 0_lcount; const auto totalLines = endLine - initialLine; for ( ;; ) { PartialSearchResults matchResults; processMatchQueue.wait_dequeue( cToken, matchResults ); LOG( logDEBUG ) << "Combining match results from " << matchResults.chunkStart; if ( matchResults.processedLines.get() ) { maxLength = qMax( maxLength, matchResults.maxLength ); nbMatches += LinesCount( static_cast<LinesCount::UnderlyingType>( matchResults.matchingLines.size() ) ); const auto processedLines = LinesCount{ matchResults.chunkStart.get() + matchResults.processedLines.get() }; totalProcessedLines += matchResults.processedLines; // After each block, copy the data to shared data // and update the client searchData.addAll( maxLength, matchResults.matchingLines, processedLines ); LOG( logDEBUG ) << "done Searching chunk starting at " << matchResults.chunkStart << ", " << matchResults.processedLines << " lines read."; blocksDone.release( matchResults.processedLines.get() ); } else { matchersDone++; } const int percentage = static_cast<int>( std::floor( 100.f * ( totalProcessedLines ).get() / totalLines.get() ) ); if ( percentage > reportedPercentage || nbMatches > reportedMatches ) { emit searchProgressed( nbMatches, std::min( 99, percentage ), initialLine ); reportedPercentage = percentage; reportedMatches = nbMatches; } if ( matchersDone == matchers.size() ) { searchCompleted.release(); return; } } } ); auto pToken = moodycamel::ProducerToken{ searchBlockQueue }; blocksDone.release( nbLinesInChunk.get() * ( static_cast<uint32_t>( matchers.size() ) + 1 ) ); for ( auto chunkStart = initialLine; chunkStart < endLine; chunkStart = chunkStart + nbLinesInChunk ) { if ( *interruptRequested_ ) break; LOG( logDEBUG ) << "Reading chunk starting at " << chunkStart; const auto linesInChunk = LinesCount( qMin( nbLinesInChunk.get(), ( endLine - chunkStart ).get() ) ); auto lines = sourceLogData_->getLines( chunkStart, linesInChunk ); LOG( logDEBUG ) << "Sending chunk starting at " << chunkStart << ", " << lines.size() << " lines read."; blocksDone.acquire( static_cast<uint32_t>( lines.size() ) ); searchBlockQueue.enqueue( pToken, { chunkStart, std::move( lines ), PartialSearchResults{} } ); LOG( logDEBUG ) << "Sent chunk starting at " << chunkStart << ", " << lines.size() << " lines read."; } for ( size_t i = 0; i < matchers.size(); ++i ) { searchBlockQueue.enqueue( pToken, { endLine, std::vector<QString>{}, PartialSearchResults{} } ); } searchCompleted.acquire(); high_resolution_clock::time_point t2 = high_resolution_clock::now(); auto duration = duration_cast<microseconds>( t2 - t1 ).count(); LOG( logINFO ) << "Searching done, took " << duration / 1000.f << " ms"; LOG( logINFO ) << "Searching perf " << static_cast<uint32_t>( std::floor( 1000 * 1000.f * ( endLine - initialLine ).get() / duration ) ) << " lines/s"; emit searchProgressed( nbMatches, 100, initialLine ); }