@@ -86,7 +86,6 @@ struct ParallelSolve::SharedData {
86
86
void reset (SharedContext& a_ctx) {
87
87
clearQueue ();
88
88
syncT.reset ();
89
- msg.clear ();
90
89
globalR.reset ();
91
90
discardVec (path);
92
91
maxConflict = globalR.current ();
@@ -99,7 +98,7 @@ struct ParallelSolve::SharedData {
99
98
workReq = 0 ;
100
99
restartReq = 0 ;
101
100
generator = nullptr ;
102
- errorCode = 0 ;
101
+ error = nullptr ;
103
102
}
104
103
void clearQueue () {
105
104
workQ.first .clear ();
@@ -207,7 +206,6 @@ struct ParallelSolve::SharedData {
207
206
bool setControl (uint32_t flags) { return (control.fetch_or (flags) & flags) != flags; }
208
207
bool clearControl (uint32_t flags) { return (control.fetch_and (~flags) & flags) == flags; }
209
208
using GeneratorPtr = std::unique_ptr<Generator>;
210
- std::string msg; // global error message
211
209
ScheduleStrategy globalR; // global restart strategy
212
210
LitVec path; // initial guiding path - typically empty
213
211
uint64_t maxConflict{0 }; // current restart limit
@@ -228,7 +226,7 @@ struct ParallelSolve::SharedData {
228
226
std::atomic<uint32_t > restartReq{0 }; // == numThreads(): restart
229
227
std::atomic<uint32_t > control{0 }; // set of active message flags
230
228
std::atomic<uint32_t > modCount{0 }; // counter for synchronizing models
231
- int32_t errorCode{ 0 }; // global error code
229
+ std::exception_ptr error{ nullptr }; // global exception
232
230
};
233
231
234
232
// post message to all threads
@@ -381,7 +379,7 @@ inline void ParallelSolve::reportProgress(const Solver& s, const char* msg) cons
381
379
}
382
380
383
381
// joins with and destroys all active threads
384
- int ParallelSolve::joinThreads () {
382
+ void ParallelSolve::joinThreads () {
385
383
uint32_t winner = thread_[master_id]->winner () ? master_id : UINT32_MAX;
386
384
// detach master only after all client threads are done
387
385
for (uint32_t i : irange (1u , shared_->nextId )) {
@@ -404,7 +402,6 @@ int ParallelSolve::joinThreads() {
404
402
shared_->nextId = 1 ;
405
403
shared_->syncT .stop ();
406
404
reportProgress (MessageEvent (*shared_->ctx ->master (), " TERMINATE" , MessageEvent::completed, shared_->syncT .total ()));
407
- return not shared_->interrupt () ? thread_[master_id]->error () : shared_->errorCode ;
408
405
}
409
406
410
407
void ParallelSolve::doStart (SharedContext& ctx, LitView assume) {
@@ -434,10 +431,13 @@ void ParallelSolve::doStop() {
434
431
shared_->generator ->notify (SharedData::Generator::done);
435
432
thread_[master_id]->join ();
436
433
}
437
- int err = joinThreads ();
434
+ joinThreads ();
438
435
shared_->generator = nullptr ;
439
436
shared_->ctx ->distributor .reset (nullptr );
440
- POTASSCO_CHECK (err == 0 , err, " %s" , shared_->msg .c_str ());
437
+ if (shared_->error && (shared_->interrupt () || thread_[master_id]->error ())) {
438
+ std::rethrow_exception (shared_->error );
439
+ }
440
+ assert (not thread_[master_id]->error ());
441
441
}
442
442
443
443
void ParallelSolve::doDetach () {
@@ -486,16 +486,10 @@ void ParallelSolve::solveParallel(uint32_t id) {
486
486
}
487
487
}
488
488
catch (const std::bad_alloc&) {
489
- exception (id, std::move (a), ENOMEM, " bad alloc" );
490
- }
491
- catch (const std::logic_error& e) {
492
- exception (id, std::move (a), Potassco::to_underlying (Potassco::Errc::invalid_argument), e.what ());
493
- }
494
- catch (const std::exception & e) {
495
- exception (id, std::move (a), Potassco::to_underlying (std::errc::interrupted), e.what ());
489
+ exception (id, std::move (a), true );
496
490
}
497
491
catch (...) {
498
- exception (id, std::move (a), Potassco::to_underlying (std::errc::interrupted), " unknown " );
492
+ exception (id, std::move (a), false );
499
493
}
500
494
assert (shared_->terminate () || thread_[id]->error ());
501
495
auto remaining = shared_->leaveAlgorithm ();
@@ -513,28 +507,36 @@ void ParallelSolve::solveParallel(uint32_t id) {
513
507
}
514
508
}
515
509
516
- void ParallelSolve::exception (uint32_t id, Path path, int e, const char * what) {
517
- try {
518
- if (not thread_[id]->setError (e) || e != ENOMEM || id == master_id) {
519
- ParallelSolve::doInterrupt ();
510
+ void ParallelSolve::exception (uint32_t id, Path path, bool oom) noexcept {
511
+ for (thread_[id]->setError ();;) {
512
+ if (id == master_id || not oom) {
520
513
if (shared_->errorSet .fetch_or (Potassco::nth_bit<uint64_t >(id)) == 0 ) {
521
- shared_->errorCode = e;
522
- shared_->msg .append (1 , ' [' ).append (std::to_string (id)).append (" ]: " ).append (what);
514
+ shared_->error = std::current_exception ();
515
+ }
516
+ ParallelSolve::doInterrupt ();
517
+ break ;
518
+ }
519
+ try {
520
+ if (path.owner () && shared_->allowSplit ()) {
521
+ shared_->pushWork (std::move (path));
523
522
}
523
+ break ;
524
524
}
525
- else if (path.owner () && shared_->allowSplit ()) {
526
- shared_->pushWork (std::move (path));
525
+ catch (...) { // we failed to push back the path and therefore can't continue
526
+ oom = false ;
527
+ path = {};
527
528
}
528
- reportProgress (thread_[id]->solver (),
529
- e == ENOMEM ? " Thread failed with out of memory" : " Thread failed with error" );
530
529
}
531
- catch (...) {
532
- ParallelSolve::doInterrupt ();
530
+ try {
531
+ reportProgress (thread_[id]->solver (), oom ? " Thread failed with out of memory" : " Thread failed with error" );
532
+ }
533
+ catch (...) { // NOLINT(bugprone-empty-catch)
534
+ // ignore exception from progress
533
535
}
534
536
}
535
537
536
538
// forced termination from outside
537
- bool ParallelSolve::doInterrupt () {
539
+ bool ParallelSolve::doInterrupt () noexcept {
538
540
// do not notify blocked threads to avoid possible
539
541
// deadlock in semaphore!
540
542
shared_->postMessage (SharedData::msg_interrupt, false );
@@ -863,14 +865,10 @@ void ParallelHandler::setThread(Clasp::mt::thread x) {
863
865
assert (not joinable () && x.joinable ());
864
866
thread_ = std::move (x);
865
867
}
866
- bool ParallelHandler::setError (int code) {
867
- error_ = static_cast <uint32_t >(code);
868
- return thread_.joinable () && not winner ();
869
- }
870
-
871
- void ParallelHandler::setWinner () { win_ = 1 ; }
868
+ void ParallelHandler::setError () noexcept { error_ = 1 ; }
869
+ void ParallelHandler::setWinner () noexcept { win_ = 1 ; }
872
870
bool ParallelHandler::winner () const { return win_ != 0 ; }
873
- int ParallelHandler::error () const { return static_cast < int >( error_) ; }
871
+ bool ParallelHandler::error () const { return error_ != 0 ; }
874
872
bool ParallelHandler::joinable () const { return thread_.joinable (); }
875
873
876
874
void ParallelHandler::clearDB (Solver* s) {
0 commit comments