Skip to content

Commit 46a9013

Browse files
authored
Merge pull request #47707 from wddgit/fixBugInEndUnfinishedLumi
Fix bug in endUnfinishedLumi
2 parents 84f274e + 107c53c commit 46a9013

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

FWCore/Concurrency/README.md

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,45 @@ The easiest way to create an `edm::WaitingTask` is to call `edm::make_waiting_ta
2121
```
2222
2323
### `edm::FinalWaitingTask`
24-
In the case where one is doing a synchronous wait on a series of asynchronous tasks, it is useful to have a special `edm::WaitingTask` that can sit on the stack and hold onto any `std::exception_ptr` which occur during the asynchronous processing.
24+
In the case where one is doing a synchronous wait on a series of asynchronous tasks, it is useful to have a special `edm::WaitingTask` that can sit on the stack and hold onto a `std::exception_ptr` if an exception is thrown during the asynchronous processing.
2525
2626
```C++
27-
edm::FinalWaitingTask finalTask;
28-
2927
oneapi::tbb::task_group group;
28+
edm::FinalWaitingTask finalTask(group);
29+
3030
doLotsOfWorkAsynchronously( edm::WaitingTaskHolder(group, &finalTask) );
3131
32-
group.wait();
33-
assert(finalTask.done());
34-
if(auto excptPtr = finalTask.exceptionPtr()) {
35-
std::throw_exception( *excptPtr );
32+
finalTask.wait();
33+
```
34+
35+
Note that the function `wait` will rethrow any exception stored in `finalTask`. There is an alternative function named `waitNoThrow` which will return the `std::exception_ptr`.
36+
37+
WARNING: It important that the finalTask not execute before completion of the construction of all `WaitingTaskHolders` that will be constructed directly from finalTask. The following would be a bug:
38+
39+
```C++
40+
oneapi::tbb::task_group group;
41+
edm::FinalWaitingTask finalTask(group);
42+
43+
doLotsOfWorkAsynchronously( edm::WaitingTaskHolder(group, &finalTask) );
44+
doMoreWorkAsynchronously( edm::WaitingTaskHolder(group, &finalTask) ); // BUG!!!
45+
46+
finalTask.wait();
47+
```
48+
49+
This will not wait for the work started in `doMoreWorkAsynchronously` to complete if the work in doLotsOfWorkAsynchronously completes before the second WaitingTaskHolder is constructed. Here is the correct pattern for this case:
50+
51+
52+
```C++
53+
oneapi::tbb::task_group group;
54+
edm::FinalWaitingTask finalTask(group);
55+
{
56+
edm::WaitingTaskHolder holder(group, &finalTask);
57+
doLotsOfWorkAsynchronously(holder);
58+
doMoreWorkAsynchronously(holder);
3659
}
60+
finalTask.wait();
3761
```
62+
3863
## `edm::WaitingTaskHolder`
3964
This class functions as a _smart pointer_ for an `edm::WaitingTask`. On construction it will increment the embedded reference count of the `edm::WaitingTask`. On either the destructor or the call to `doneWaiting(std::exception_ptr)` it will decrement the reference count. If the count goes to 0, the `edm::WaitingTaskHolder` will pass the `std::exception_ptr` onto the `edm::WaitingTask`, call `execute()` under the `tbb:task_group` given to the holder and finally call `recycle()`.
4065

FWCore/Framework/src/EventProcessor.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,8 +2012,11 @@ namespace edm {
20122012
assert(streamLumiActive_ == preallocations_.numberOfStreams());
20132013
streamLumiStatus_[0]->noMoreEventsInLumi();
20142014
streamLumiStatus_[0]->setCleaningUpAfterException(cleaningUpAfterException);
2015-
for (unsigned int i = 0; i < preallocations_.numberOfStreams(); ++i) {
2016-
streamEndLumiAsync(WaitingTaskHolder{taskGroup_, &globalWaitTask}, i);
2015+
{
2016+
WaitingTaskHolder holder{taskGroup_, &globalWaitTask};
2017+
for (unsigned int i = 0; i < preallocations_.numberOfStreams(); ++i) {
2018+
streamEndLumiAsync(holder, i);
2019+
}
20172020
}
20182021
globalWaitTask.wait();
20192022
}

0 commit comments

Comments
 (0)