@@ -78,6 +78,33 @@ namespace Rice::detail {
7878 };
7979} // namespace Rice::detail
8080
81+ template <typename T>
82+ class Channel {
83+ public:
84+ std::queue<T> queue;
85+ std::mutex mutex;
86+ std::condition_variable cv;
87+
88+ void send (T message) {
89+ std::lock_guard<std::mutex> guard (mutex);
90+ queue.push (message);
91+ cv.notify_one ();
92+ }
93+
94+ template <typename U, typename V>
95+ std::optional<T> recv_timeout (const std::chrono::duration<U, V>& duration) {
96+ T message;
97+ std::unique_lock<std::mutex> lock (mutex);
98+ auto time = std::chrono::system_clock::now () + duration;
99+ if (!cv.wait_until (lock, time, [&] { return !queue.empty (); })) {
100+ return std::nullopt ;
101+ }
102+ message = std::move (queue.front ());
103+ queue.pop ();
104+ return message;
105+ }
106+ };
107+
81108void init_constraint (Rice::Module& m) {
82109 Rice::define_class_under<Domain>(m, " Domain" )
83110 .define_constructor (Rice::Constructor<Domain, int64_t , int64_t >())
@@ -436,9 +463,7 @@ void init_constraint(Rice::Module& m) {
436463 m.Add (NewSatParameters (parameters));
437464
438465 std::atomic<bool > done{false };
439- std::queue<CpSolverResponse> queue;
440- std::mutex mutex;
441- std::condition_variable cv;
466+ Channel<CpSolverResponse> channel;
442467 Rice::Object ruby_thread;
443468 std::optional<Rice::Exception> exception;
444469
@@ -454,28 +479,22 @@ void init_constraint(Rice::Module& m) {
454479 return Rice::detail::no_gvl ([&]() {
455480 while (true ) {
456481 if (done.load ()) {
457- std::lock_guard<std::mutex> guard (mutex);
458- if (queue.empty ()) {
482+ std::lock_guard<std::mutex> guard (channel. mutex );
483+ if (channel. queue .empty ()) {
459484 break ;
460485 }
461486 }
462487
463488 while (true ) {
464- CpSolverResponse r;
465- {
466- std::unique_lock<std::mutex> lock (mutex);
467- auto time = std::chrono::system_clock::now () + std::chrono::milliseconds (10 );
468- if (!cv.wait_until (lock, time, [&] { return !queue.empty (); })) {
469- break ;
470- }
471- r = std::move (queue.front ());
472- queue.pop ();
489+ std::optional<CpSolverResponse> r = channel.recv_timeout (std::chrono::milliseconds (10 ));
490+ if (!r) {
491+ break ;
473492 }
474493
475494 bool stop = false ;
476495 with_gvl ([&]() {
477496 try {
478- callback.call (" response=" , r);
497+ callback.call (" response=" , r. value () );
479498 callback.call (" on_solution_callback" );
480499 stop = static_cast <bool >(callback.attr_get (" @stopped" ));
481500 } catch (const Rice::Exception& e) {
@@ -510,9 +529,7 @@ void init_constraint(Rice::Module& m) {
510529
511530 m.Add (NewFeasibleSolutionObserver (
512531 [&](const CpSolverResponse& r) {
513- std::lock_guard<std::mutex> guard (mutex);
514- queue.push (r);
515- cv.notify_one ();
532+ channel.send (r);
516533 })
517534 );
518535 }
0 commit comments