Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
solve_interrupter.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <atomic>
17#include <functional>
18#include <memory>
19#include <optional>
20#include <utility>
21
22#include "absl/synchronization/mutex.h"
26
27namespace operations_research {
28
30 const absl::MutexLock lock(&mutex_);
31
32 // Here we don't use compare_exchange_strong since we need to hold the lock
33 // before changing the value of interrupted_ anyway. So there is no need to
34 // use this complex function.
35 if (interrupted_.load()) {
36 // We must not call the callbacks more than once.
37 return;
38 }
39
40 // We need to change this value while holding the lock since in
41 // AddInterruptionCallback() we must know if we need to call the new callback
42 // of if this function has called it.
43 interrupted_ = true;
44
45 // We are holding the lock while calling callbacks. This make it impossible to
46 // call Interrupt(), AddInterruptionCallback(), or
47 // RemoveInterruptionCallback() from a callback but it ensures that external
48 // code that can modify callbacks_ will wait the end of Interrupt.
49 for (const auto& [callback_id, callback] : callbacks_) {
50 callback();
51 }
52}
53
54SolveInterrupter::CallbackId SolveInterrupter::AddInterruptionCallback(
55 Callback callback) const {
56 const absl::MutexLock lock(&mutex_);
57
58 // We must make this call while holding the lock since we want to be sure that
59 // the calls to the callbacks_ won't occur before we registered the new
60 // one. If we were not holding the lock, this could return false and before we
61 // could add the new callback to callbacks_, the Interrupt() function may
62 // still have called them.
63 //
64 // We make the call before putting the callback in the map to since we need to
65 // move it in place.
66 if (interrupted_.load()) {
67 callback();
68 }
69
70 const CallbackId id = next_callback_id_;
71 ++next_callback_id_;
72 CHECK(callbacks_.try_emplace(id, std::move(callback)).second);
73 return id;
74}
75
77 const absl::MutexLock lock(&mutex_);
78 CHECK_EQ(callbacks_.erase(id), 1) << "unregistered callback id: " << id;
79}
80
82 const SolveInterrupter* const interrupter,
84 : interrupter_(interrupter),
85 callback_id_(
86 interrupter != nullptr
87 ? std::make_optional(
88 interrupter->AddInterruptionCallback(std::move(callback)))
89 : std::nullopt) {}
90
94
96 if (callback_id_) {
97 CHECK_NE(interrupter_, nullptr);
98 interrupter_->RemoveInterruptionCallback(*callback_id_);
99 callback_id_.reset();
100 }
101}
102
103} // namespace operations_research
~ScopedSolveInterrupterCallback()
Removes the callback if necessary.
ScopedSolveInterrupterCallback(const SolveInterrupter *interrupter, SolveInterrupter::Callback callback)
void RemoveInterruptionCallback(CallbackId id) const
CallbackId AddInterruptionCallback(Callback callback) const
MPCallback * callback
In SWIG mode, we don't want anything besides these top-level includes.
STL namespace.