Skip to content

Commit e121cdc

Browse files
committed
P3832R1 and P3833R2
Signed-off-by: Ted Lyngmo <ted@lyncon.se>
1 parent bbad9cf commit e121cdc

2 files changed

Lines changed: 23 additions & 16 deletions

File tree

papers/P3832.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,25 @@
22
title: "Timed lock algorithms for multiple lockables"
33
---
44

5-
- **Document number:** P3832R0
5+
- **Document number:** P3832R1
66
- **Date:** @DATE@
77
- **Audience:** Library Evolution Working Group
88
- **Project:** ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
99
- **Reply-to:** Ted Lyngmo <ted@lyncon.se>
1010

1111
## Revision History
1212

13+
### R1
14+
15+
- Added link to reference implementation.
16+
17+
Modifications after `2025-11_Kona:SG1-P3832R0` meeting:
18+
19+
- Added a note that an implementation should ensure that `try_lock_until()` does not consistently return ≥ 0 in the absence of contending mutex acquisitions.
20+
- Clarified that no call to `try_lock_for()` or `try_lock_until()` is made while holding a lock on any argument.
21+
- Added `Throws` clause to `try_lock_until`.
22+
- Changed "the index of the last lockable for which locking failed" to "the index of the lockable for which `try_lock_until()` or `try_lock_for()` failed due to `abs_time` being reached" in Effects and Returns.
23+
1324
## Abstract
1425

1526
C++11 introduced `std::lock` and `std::try_lock` (and C++17 introduced `std::scoped_lock`) to simplify deadlock-free acquisition of multiple lockables. These algorithms support *BasicLockable* and *Lockable* objects, but there is currently no facility for timed acquisition of multiple *TimedLockable* objects.
@@ -59,7 +70,7 @@ These extend the `std::lock` family of functions to timed lockables, enabling co
5970
6071
## 5. Proposed Wording
6172
62-
The following changes are relative to N5008.
73+
The following changes are relative to N5014.
6374
6475
In 32.6.6, Generic locking algorithms [thread.lock.algorithm], after point 5:
6576
@@ -70,14 +81,11 @@ int try_lock_until(const chrono::time_point<Clock, Duration>& abs_time, Ls&... l
7081

7182
**6** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Preconditions*: Each template parameter type in `Ls` meets the *Cpp17TimedLockable* requirements.
7283

73-
**7** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Effects*: Attempts to obtain ownership of all arguments via repeated calls to `try_lock_until()`, `try_lock_for()`, `try_lock()` or `unlock()` on each argument. The sequence of calls does not result in deadlock, but is otherwise unspecified.
74-
75-
- If all locks are acquired before `abs_time` has passed, returns `-1`.
76-
- If the time point `abs_time` is reached before all locks are acquired, releases any locks it holds and returns the index of the last lockable for which locking failed.
84+
**7** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Effects*: Attempts to obtain ownership of all arguments via repeated calls to `try_lock_until()`, `try_lock_for()`, `try_lock()` or `unlock()` on each argument. The sequence of calls does not result in deadlock. No call to `try_lock_for()` or `try_lock_until()` is made while holding a lock on any argument, but the sequence is otherwise unspecified. If all locks are acquired before `abs_time` has passed, returns `-1`. If the time point `abs_time` is reached before all locks are acquired, releases any locks it holds and returns the index of the lockable for which `try_lock_until()` or `try_lock_for()` failed due to `abs_time` being reached. If a call to `try_lock_until()`, `try_lock_for()` or `try_lock()` throws an exception, `unlock()` is called on any object locked by this algorithm prior to the exception, and the exception is rethrown.<br>An implementation should ensure that `try_lock_until()` does not consistently return ≥ 0 in the absence of contending mutex acquisitions.
7785

78-
If a call to `try_lock_until()`, `try_lock_for()` or `try_lock()` throws an exception, `unlock()` is called on any object locked by this algorithm prior to the exception, and the exception is rethrown.
86+
**8** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Returns*: `-1` if all locks were obtained, otherwise the index of the lockable for which `try_lock_until()` or `try_lock_for()` failed due to `abs_time` being reached.
7987

80-
**8** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Returns*: `-1` if all locks were obtained, otherwise the index of the last lockable for which locking failed.
88+
**9** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Throws*: Any exception thrown by the lockable `try_lock_until()`, `try_lock_for()`, or `try_lock()` functions.
8189

8290
```cpp
8391
template <class Rep, class Period, class... Ls>
@@ -86,11 +94,7 @@ int try_lock_for(const chrono::duration<Rep, Period>& rel_time, Ls&... ls);
8694
8795
**9** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Preconditions*: Each template parameter type in `Ls` meets the *Cpp17TimedLockable* requirements.
8896
89-
**10** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Effects*: Equivalent to:
90-
91-
```cpp
92-
return try_lock_until(chrono::steady_clock::now() + rel_time, ls...);
93-
```
97+
**10** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*Effects*: Equivalent to:<br>`return try_lock_until(chrono::steady_clock::now() + rel_time, ls...);`
9498
9599
## 6. Example
96100
@@ -109,6 +113,8 @@ if (std::try_lock_for(100ms, m1, m2) == -1) {
109113

110114
Existing implementations of `std::lock` already use a deadlock-avoidance algorithm. Using the gcc implementation as an example, instead of locking one with `m.lock()` and using `std::try_lock()` on the rest, the algorithm could start locking one with `m.try_lock_until(tp)`. [Example at Compiler Explorer](https://godbolt.org/z/Ya7Pbq85P)
111115

116+
A reference implementation is available at [github.com/bemanproject/timed_lock_alg](https://github.com/bemanproject/timed_lock_alg).
117+
112118
## 8. Acknowledgments
113119

114120
The std-proposals mailing list:
@@ -123,4 +129,4 @@ Reference implementation:
123129

124130
## 9. References
125131

126-
- N5008: Working Draft, Programming Languages — C++ (C++26).
132+
- N5014: Working Draft, Programming Languages — C++ (C++26).

papers/P3833.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: "`std::multi_lock`"
33
---
44

5-
- **Document number:** P3833R2a
5+
- **Document number:** P3833R2
66
- **Date:** @DATE@
77
- **Audience:** LEWGI/SG1
88
- **Project:** ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
@@ -13,6 +13,7 @@ title: "`std::multi_lock`"
1313
### R2
1414

1515
- Removed _Attempts to lock all mutexes using a deadlock-avoidance algorithm until `abs_time`_ from `try_lock_until` _Effects_ after unanimous vote in Croydon.
16+
- Clarified that no call to `try_lock_for()` or `try_lock_until()` is made while holding a lock on any element of `pm` in `try_lock_until` _Effects_, to harmonize with the updated wording in P3832.
1617

1718
### R1
1819

@@ -506,7 +507,7 @@ template<class Clock, class Duration>
506507

507508
**14** *Preconditions*: All types in `MutexTypes` meet the *Cpp17TimedLockable* requirements (32.2.5.4).
508509

509-
**15** *Effects*: If `sizeof...(MutexTypes)` equals 0, returns -1. Otherwise, if `sizeof...(MutexTypes)` equals 1, calls `get<0>(pm)->try_lock_until(abs_time)` and returns -1 if successful, 0 otherwise. Otherwise, uses an algorithm similar to `lock()` but with timed operations respecting `abs_time`.
510+
**15** *Effects*: If `sizeof...(MutexTypes)` equals 0, returns -1. Otherwise, if `sizeof...(MutexTypes)` equals 1, calls `get<0>(pm)->try_lock_until(abs_time)` and returns -1 if successful, 0 otherwise. Otherwise, uses an algorithm similar to `lock()` but with timed operations respecting `abs_time`. No call to `try_lock_for()` or `try_lock_until()` is made while holding a lock on any element of `pm`.
510511

511512
**16** *Postconditions*: `owns` is `true` if the return value equals -1, otherwise `false`.
512513

0 commit comments

Comments
 (0)