Skip to content

Commit e450dfe

Browse files
committed
Adjust the try_lock_until algorithm to match the wording in P3832R2
Since a timed lockable's try_lock_until will not return failure in case the time given has already expired, but instead return this->try_lock(), there was a theoretical possibility of never getting out of the loop. It was essentially possible to get into this situation: m1.try_lock_until(expired_tp); // succeeds m2.try_lock(); // fails m2.try_lock_until(expired_tp); // succeeds m1.try_lock(); // fails // back to the original situation and it could keep going The remedy was to add wording about "the above steps are repeated until the time point abs_time has been reached" which made it necessary to do a Clock::now() call before trying a new sequence (sorry Bosse). Signed-off-by: Ted Lyngmo <ted@lyncon.se>
1 parent 26acd25 commit e450dfe

2 files changed

Lines changed: 8 additions & 7 deletions

File tree

include/beman/timed_lock_alg/mutex.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ struct result {
6767
bool retry;
6868
};
6969
//-------------------------------------------------------------------------
70-
template <class Timepoint, class Locks, class... Seqs>
71-
int try_lock_until_impl(const Timepoint& end_time, Locks locks, type_pack<Seqs...>) {
70+
template <class Clock, class Duration, class Locks, class... Seqs>
71+
int try_lock_until_impl(const std::chrono::time_point<Clock, Duration>& end_time, Locks locks, type_pack<Seqs...>) {
7272
// an array with one function per lockable/sequence to try:
73-
constexpr std::array<result (*)(const Timepoint&, Locks&), sizeof...(Seqs)> seqs{
74-
{+[](const Timepoint& tp, Locks& lks) {
73+
constexpr std::array<result (*)(const std::chrono::time_point<Clock, Duration>&, Locks&), sizeof...(Seqs)> seqs{
74+
{+[](const std::chrono::time_point<Clock, Duration>& tp, Locks& lks) {
7575
return []<class Tp, std::size_t I0, std::size_t... Is>(
7676
const Tp& itp, Locks& lcks, std::index_sequence<I0, Is...>) -> result {
7777
if (std::unique_lock first{std::get<I0>(lcks), itp}) {
@@ -80,9 +80,10 @@ int try_lock_until_impl(const Timepoint& end_time, Locks locks, type_pack<Seqs..
8080
first.release();
8181
return {-1, false}; // success
8282
}
83-
// return the index to try_lock_until next round
83+
// return the index to try_lock_until next round or the index which failed to lock
84+
// in case time has run out
8485
constexpr std::array idxs{static_cast<int>(Is)...};
85-
return {idxs[static_cast<std::size_t>(res)], true};
86+
return {idxs[static_cast<std::size_t>(res)], Clock::now() < itp};
8687
}
8788
// timeout
8889
return {static_cast<int>(I0), false};

tests/beman/timed_lock_alg/try_lock.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,5 @@ TEST(TryLockIntegration, SucceedWithThreeInTrickySequence) {
229229
m0.should_fail = false; // unblock m0; try_lock(m1,m2) → both succeed → done
230230
});
231231

232-
EXPECT_EQ(-1, tla::try_lock_for(no_duration, m0, m1, m2));
232+
EXPECT_EQ(-1, tla::try_lock_for(24h, m0, m1, m2));
233233
}

0 commit comments

Comments
 (0)