| 560 | */ |
| 561 | template <typename Func> |
| 562 | BackgroundThread* thenBackgroundWithProgress( |
| 563 | QWidget* parent, const QString& title, const QString& text, const QString& cancel, Func&& func) |
| 564 | { |
| 565 | m_then.push_back( |
| 566 | {MainThread, [=](QVariant v) { |
| 567 | QVariant result; |
| 568 | // Since the task starts immediately, we need to hold a lock to its value |
| 569 | // Just in case it manages to get to the part of the lambda where it reads the value |
| 570 | // before this thread actually assigns it. |
| 571 | // This is *probably* not a race in practice due to the variable being stored on the stack before |
| 572 | // construction. |
| 573 | std::mutex taskMutex; |
| 574 | taskMutex.lock(); |
| 575 | ProgressTask* task; |
| 576 | task = new ProgressTask(parent, title, text, cancel, [&](ProgressFunction progress) { |
| 577 | auto innerProgress = [=](size_t cur, size_t max) { |
| 578 | // Fix dialog disappearing if the backgrounded task thinks it's done |
| 579 | if (cur >= max) |
| 580 | { |
| 581 | cur = max - 1; |
| 582 | } |
| 583 | return progress(cur, max); |
| 584 | }; |
| 585 | try |
| 586 | { |
| 587 | // See above comment about race conditions |
| 588 | taskMutex.lock(); |
| 589 | ProgressTask* innerTask = task; |
| 590 | taskMutex.unlock(); |
| 591 | |
| 592 | if constexpr (std::is_void_v< |
| 593 | std::invoke_result_t<Func, QVariant, ProgressTask*, ProgressFunction>>) |
| 594 | { |
| 595 | func(v, innerTask, innerProgress); |
| 596 | } |
| 597 | else |
| 598 | { |
| 599 | result = func(v, innerTask, innerProgress); |
| 600 | } |
| 601 | // And actually report success |
| 602 | progress(1, 1); |
| 603 | } |
| 604 | catch (...) |
| 605 | { |
| 606 | progress(1, 1); |
| 607 | std::rethrow_exception(std::current_exception()); |
| 608 | }; |
| 609 | }); |
| 610 | taskMutex.unlock(); |
| 611 | task->wait(); |
| 612 | |
| 613 | return result; |
| 614 | }}); |
| 615 | return this; |
| 616 | } |
| 617 | |
| 618 | /*! |
| 619 | Add a function to run on a background thread in the event an exception is thrown |