Skip to content

Commit c87eee8

Browse files
committed
Fix correct TBB pool closure in dpl-eventgen with TTL
1 parent aa95339 commit c87eee8

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

‎Generators/include/Generators/GeneratorHybrid.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class GeneratorHybrid : public Generator
6464
Bool_t generateEvent() override;
6565
Bool_t importParticles() override;
6666
void updateHeader(o2::dataformats::MCEventHeader* eventHeader) override;
67+
void stop() override; // end-of-stream hook that closes the TBB task arena
6768

6869
Bool_t parseJSON(const std::string& path);
6970
Bool_t confSetter(const auto& gen);

‎Generators/src/GeneratorHybrid.cxx‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// or submit itself to any jurisdiction.
1111

1212
#include "Generators/GeneratorHybrid.h"
13+
#include <chrono>
1314
#include <fairlogger/Logger.h>
1415
#include <algorithm>
1516
#include <tbb/concurrent_queue.h>
@@ -191,7 +192,24 @@ GeneratorHybrid::GeneratorHybrid(const std::string& inputgens)
191192
GeneratorHybrid::~GeneratorHybrid()
192193
{
193194
LOG(info) << "Destructor of generator hybrid called";
195+
// stop() is the designated shutdown hook (called via GeneratorService::stopGenerators),
196+
// normally running end-of-stream, in which case this is a no-op. It is not reached on every exit path, e.g. when the
197+
// driver quits before the event budget or the TTL is up, so it is repeated here.
198+
stop();
199+
}
200+
201+
void GeneratorHybrid::stop()
202+
{
194203
mStopFlag = true;
204+
// The worker lambdas reference mInputTaskQueue, mResultQueue and mTaskArena, which are
205+
// destroyed together with this object, so they must not be left running.
206+
// We wait for the thread to finish, which will happen once the worker lambdas notice mStopFlag.
207+
if (mTBBTaskPoolRunner.joinable()) {
208+
auto t0 = std::chrono::steady_clock::now();
209+
mTBBTaskPoolRunner.join();
210+
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - t0).count();
211+
LOG(info) << "HybridGen: stop() joined TBB task pool after " << ms << " ms";
212+
}
195213
}
196214

197215
Bool_t GeneratorHybrid::Init()
@@ -320,7 +338,7 @@ Bool_t GeneratorHybrid::Init()
320338
// }
321339
}
322340
bool isTriggered = false;
323-
while (!isTriggered) {
341+
while (!isTriggered && !mStopFlag) {
324342
generator->clearParticles();
325343
generator->generateEvent();
326344
generator->importParticles();
@@ -355,8 +373,8 @@ Bool_t GeneratorHybrid::Init()
355373

356374
// let the TBB task system run in it's own thread
357375
mTBBTaskPoolRunner = std::thread([this, worker_function]() { mTaskArena.execute([&]() { tbb::parallel_for(0, mTaskArena.max_concurrency(), [&](int) { worker_function(); }); }); });
358-
mTBBTaskPoolRunner.detach(); // detaching because we don't like to wait on the thread to finish
359-
// some of the generators might still be generating when we are done
376+
// NOTE: thread deliberately NOT detached. We never wait for it during the run, but the
377+
// pool must be joined in the destructor before the queues and the arena are destroyed.
360378

361379
// let's also push initial generation tasks for each event generator
362380
for (size_t genindex = 0; genindex < gens.size(); ++genindex) {

0 commit comments

Comments
 (0)