Skip to content

Commit a7b042a

Browse files
committed
Add some documentation for System.Threading.Lock APIs
1 parent d4a3c0c commit a7b042a

File tree

3 files changed

+183
-35
lines changed

3 files changed

+183
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Threading;
3+
4+
// <Snippet1>
5+
public sealed class ExampleDataStructure
6+
{
7+
private readonly Lock _lockObj = new();
8+
9+
private void Modify()
10+
{
11+
lock (_lockObj)
12+
{
13+
// Critical section associated with _lockObj
14+
}
15+
16+
using (_lockObj.EnterScope())
17+
{
18+
// Critical section associated with _lockObj
19+
}
20+
21+
_lockObj.Enter();
22+
try
23+
{
24+
// Critical section associated with _lockObj
25+
}
26+
finally { _lockObj.Exit(); }
27+
28+
if (_lockObj.TryEnter())
29+
{
30+
try
31+
{
32+
// Critical section associated with _lockObj
33+
}
34+
finally { _lockObj.Exit(); }
35+
}
36+
}
37+
}
38+
// </Snippet1>

xml/System.Threading/Lock+Scope.xml

+25-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,18 @@
2424
</Attribute>
2525
</Attributes>
2626
<Docs>
27-
<summary>To be added.</summary>
28-
<remarks>To be added.</remarks>
27+
<summary>Represents a <see cref="T:System.Threading.Lock" /> that may have been entered.</summary>
28+
<remarks>
29+
<format type="text/markdown"><![CDATA[
30+
31+
## Remarks
32+
33+
This type is intended to be used with the <xref:System.Threading.Lock.EnterScope%2A> method, which returns a <xref:System.Threading.Lock.Scope> representing the lock that was entered, along with a language construct that would automatically dispose the <xref:System.Threading.Lock.Scope>, such as with the C# `using` keyword. Disposing the `Scope` exits the lock. Ensure that <xref:System.Threading.Lock.Scope.Dispose%2A> is called even in case of exceptions.
34+
35+
For more information, see <xref:System.Threading.Lock.EnterScope%2A> and the Remarks for <xref:System.Threading.Lock>.
36+
37+
]]></format>
38+
</remarks>
2939
</Docs>
3040
<Members>
3141
<Member MemberName="Dispose">
@@ -45,8 +55,19 @@
4555
</ReturnValue>
4656
<Parameters />
4757
<Docs>
48-
<summary>To be added.</summary>
49-
<remarks>To be added.</remarks>
58+
<summary>Exits the lock if the <see cref="T:System.Threading.Lock.Scope" /> represents a lock that was entered.</summary>
59+
<remarks>
60+
<format type="text/markdown"><![CDATA[
61+
62+
## Remarks
63+
64+
If the current thread holds the lock multiple times, such as recursively, the lock is exited only once. The current thread should ensure that each <xref:System.Threading.Lock.EnterScope%2A> is matched with a <xref:System.Threading.Lock.Scope.Dispose%2A> on the `Scope` returned by `EnterScope`.
65+
66+
For more information, see the Remarks for <xref:System.Threading.Lock.Scope>.
67+
68+
]]></format>
69+
</remarks>
70+
<exception cref="System.Threading.SynchronizationLockException">The <see cref="T:System.Threading.Lock.Scope" /> represents a lock that was entered and the current thread does not hold the lock.</exception>
5071
</Docs>
5172
</Member>
5273
</Members>

xml/System.Threading/Lock.xml

+120-31
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,36 @@
1313
<BaseTypeName>System.Object</BaseTypeName>
1414
</Base>
1515
<Interfaces />
16-
<Attributes>
17-
<Attribute>
18-
<AttributeName Language="C#">[System.Runtime.Versioning.RequiresPreviewFeatures]</AttributeName>
19-
<AttributeName Language="F#">[&lt;System.Runtime.Versioning.RequiresPreviewFeatures&gt;]</AttributeName>
20-
</Attribute>
21-
</Attributes>
16+
<Attributes />
2217
<Docs>
23-
<summary>To be added.</summary>
24-
<remarks>To be added.</remarks>
18+
<summary>Provides a mechanism for achieving mutual exclusion in regions of code between different threads.</summary>
19+
<remarks>
20+
<format type="text/markdown"><![CDATA[
21+
22+
## Remarks
23+
24+
The <xref:System.Threading.Lock> class can be used to define regions of code that require mutually exclusive access between threads of a process, commonly called critical sections, to prevent concurrent accesses to a resource. A `Lock` may be entered and exited, where the region of code between the enter and exit would be a critical section associated with the lock. A thread that enters a lock is said to hold or own the lock until it exits the lock. At most one thread may hold a lock at any given time. A thread may hold multiple locks. A thread may enter a lock multiple times before exiting it, such as recursively. A thread that cannot enter a lock immediately may wait until the lock can be entered or until a specified timeout expires.
25+
26+
When using the <xref:System.Threading.Lock.Enter%2A> or <xref:System.Threading.Lock.TryEnter%2A> methods to enter a lock:
27+
- Ensure that the thread exits the lock with <xref:System.Threading.Lock.Exit%2A> even in case of exceptions, such as in C# by using a `try/finally` block.
28+
- When the lock is being entered and exited in a C# `async` method, ensure that there is no `await` between the enter and exit. Locks are held by threads and the code following an `await` may run on a different thread.
29+
30+
It is recommended to use the <xref:System.Threading.Lock.EnterScope%2A> method with a safe dispose pattern such as with the C# `using` keyword, or to use the C# `lock` keyword, as these ensure that the lock is exited in exceptional cases and may also have performance benefits over using `Enter/TryEnter` and `Exit`. The following code fragment illustrates various patterns for entering and exiting a lock.
31+
32+
:::code language="csharp" source="~/snippets/csharp/System.Threading/Lock/Overview/UsagePatterns.cs" id="Snippet1":::
33+
34+
When using the C# `lock` keyword or similar to enter and exit a lock, the type of the expression must be precisely `System.Threading.Lock`. If the type of the expression is anything else, such as `Object` or a generic type like `T`, a different implementation that is not interchangeable may be used instead (such as <xref:System.Threading.Monitor>). For more information, see the relevant [the compiler speclet](https://github.com/dotnet/csharplang/blob/main/proposals/lock-object.md).
35+
36+
<xref:System.Threading.Thread.Interrupt%2A> can interrupt threads that are waiting to enter a lock. On Windows STA threads, waits for locks allow message pumping that may run other code on the same thread during a wait. Some features of the waits may be overridden by a custom <xref:System.Threading.SynchronizationContext>.
37+
38+
> [!NOTE]
39+
> A thread that enters a lock, including multiple times such as recursively, must exit the lock the same number of times to fully exit the lock and allow other threads to enter the lock. If a thread exits while holding a `Lock`, the behavior of the `Lock` becomes undefined.
40+
41+
> [!CAUTION]
42+
> If on a code path a thread may enter multiple locks before exiting them, ensure that all code paths that may enter any two of those locks on the same thread enter them in the same order. Otherwise, it could lead to deadlocks. For example, consider that on one code path thread `T1` enters lock `L1` then lock `L2` before exiting both, and on another code path thread `T2` enters both locks in the inverse order. In that scenario, it would be possible for the following order of events to occur: `T1` enters `L1`, `T2` enters `L2`, `T1` tries to enter `L2` and waits, `T2` tries to enter `L1` and waits - there's a deadlock between `T1` and `T2` that cannot be resolved, and any other threads that try to enter either lock in the future will also hang.
43+
44+
]]></format>
45+
</remarks>
2546
</Docs>
2647
<Members>
2748
<Member MemberName=".ctor">
@@ -37,8 +58,7 @@
3758
</AssemblyInfo>
3859
<Parameters />
3960
<Docs>
40-
<summary>To be added.</summary>
41-
<remarks>To be added.</remarks>
61+
<summary>Initializes a new instance of the <see cref="T:System.Threading.Lock" /> class.</summary>
4262
</Docs>
4363
</Member>
4464
<Member MemberName="Enter">
@@ -58,8 +78,19 @@
5878
</ReturnValue>
5979
<Parameters />
6080
<Docs>
61-
<summary>To be added.</summary>
62-
<remarks>To be added.</remarks>
81+
<summary>Enters the lock, waiting if necessary until the lock can be entered.</summary>
82+
<remarks>
83+
<format type="text/markdown"><![CDATA[
84+
85+
## Remarks
86+
87+
When the method returns, the current thread would be the only thread that holds the lock. If the lock cannot be entered immediately, the method waits until the lock can be entered. If the lock is already held by the current thread, the lock is entered again. The current thread should exit the lock as many times as it had entered the lock to fully exit the lock and allow other threads to enter the lock.
88+
89+
For more information, see the Remarks for <xref:System.Threading.Lock>.
90+
91+
]]></format>
92+
</remarks>
93+
<exception cref="System.Threading.LockRecursionException">The lock has reached the limit of repeated enters by the current thread. The limit is implementation-defined and is intended to be high enough that it would not be reached in normal situations.</exception>
6394
</Docs>
6495
</Member>
6596
<Member MemberName="EnterScope">
@@ -79,9 +110,22 @@
79110
</ReturnValue>
80111
<Parameters />
81112
<Docs>
82-
<summary>To be added.</summary>
83-
<returns>To be added.</returns>
84-
<remarks>To be added.</remarks>
113+
<summary>Enters the lock, waiting if necessary until the lock can be entered.</summary>
114+
<returns>A <see cref="T:System.Threading.Lock.Scope"/> that may be disposed to exit the lock.</returns>
115+
<remarks>
116+
<format type="text/markdown"><![CDATA[
117+
118+
## Remarks
119+
120+
If the lock cannot be entered immediately, the method waits until the lock can be entered. If the lock is already held by the current thread, the lock is entered again. The current thread should dispose the returned <xref:System.Threading.Lock.Scope> to exit the lock as many times as it had entered the lock to fully exit the lock and allow other threads to enter the lock.
121+
122+
This method is intended to be used along with a language construct that would automatically dispose the <xref:System.Threading.Lock.Scope>, such as with the C# `using` keyword.
123+
124+
For more information, see the Remarks for <xref:System.Threading.Lock>.
125+
126+
]]></format>
127+
</remarks>
128+
<exception cref="System.Threading.LockRecursionException">The lock has reached the limit of repeated enters by the current thread. The limit is implementation-defined and is intended to be high enough that it would not be reached in normal situations.</exception>
85129
</Docs>
86130
</Member>
87131
<Member MemberName="Exit">
@@ -101,8 +145,19 @@
101145
</ReturnValue>
102146
<Parameters />
103147
<Docs>
104-
<summary>To be added.</summary>
105-
<remarks>To be added.</remarks>
148+
<summary>Exits the lock.</summary>
149+
<remarks>
150+
<format type="text/markdown"><![CDATA[
151+
152+
## Remarks
153+
154+
If the current thread holds the lock multiple times, such as recursively, the lock is exited only once. The current thread should ensure that each enter is matched with an exit.
155+
156+
For more information, see the Remarks for <xref:System.Threading.Lock>.
157+
158+
]]></format>
159+
</remarks>
160+
<exception cref="System.Threading.SynchronizationLockException">The current thread does not hold the lock.</exception>
106161
</Docs>
107162
</Member>
108163
<Member MemberName="IsHeldByCurrentThread">
@@ -121,9 +176,8 @@
121176
<ReturnType>System.Boolean</ReturnType>
122177
</ReturnValue>
123178
<Docs>
124-
<summary>To be added.</summary>
125-
<value>To be added.</value>
126-
<remarks>To be added.</remarks>
179+
<summary>Indicates whether the lock is held by the current thread.</summary>
180+
<value><see langword="true" /> if the current thread holds the lock; otherwise, <see langword="false" />.</value>
127181
</Docs>
128182
</Member>
129183
<Member MemberName="TryEnter">
@@ -143,9 +197,20 @@
143197
</ReturnValue>
144198
<Parameters />
145199
<Docs>
146-
<summary>To be added.</summary>
147-
<returns>To be added.</returns>
148-
<remarks>To be added.</remarks>
200+
<summary>Tries to enter the lock without waiting.</summary>
201+
<returns><see langword="true" /> if the lock was entered by the current thread; otherwise, <see langword="false" />.</returns>
202+
<remarks>
203+
<format type="text/markdown"><![CDATA[
204+
205+
## Remarks
206+
207+
When the method returns `true`, the current thread would be the only thread that holds the lock. If the lock cannot be entered immediately, the method returns `false` without waiting for the lock. If the lock is already held by the current thread, the lock is entered again. The current thread should exit the lock as many times as it had entered the lock to fully exit the lock and allow other threads to enter the lock.
208+
209+
For more information, see the Remarks for <xref:System.Threading.Lock>.
210+
211+
]]></format>
212+
</remarks>
213+
<exception cref="System.Threading.LockRecursionException">The lock has reached the limit of repeated enters by the current thread. The limit is implementation-defined and is intended to be high enough that it would not be reached in normal situations.</exception>
149214
</Docs>
150215
</Member>
151216
<Member MemberName="TryEnter">
@@ -167,10 +232,22 @@
167232
<Parameter Name="millisecondsTimeout" Type="System.Int32" />
168233
</Parameters>
169234
<Docs>
170-
<param name="millisecondsTimeout">To be added.</param>
171-
<summary>To be added.</summary>
172-
<returns>To be added.</returns>
173-
<remarks>To be added.</remarks>
235+
<param name="millisecondsTimeout">The number of milliseconds to wait until the lock can be entered. The value may be <see cref="F:System.Threading.Timeout.Infinite" /> (<code>-1</code>) to wait indefinitely, or <code>0</code> to not wait.</param>
236+
<summary>Tries to enter the lock, waiting if necessary for the specified number of milliseconds until the lock can be entered.</summary>
237+
<returns><see langword="true" /> if the lock was entered by the current thread; otherwise, <see langword="false" />.</returns>
238+
<remarks>
239+
<format type="text/markdown"><![CDATA[
240+
241+
## Remarks
242+
243+
When the method returns `true`, the current thread would be the only thread that holds the lock. If the lock cannot be entered immediately, the method waits until the lock can be entered or until the timeout specified by the `millisecondsTimeout` parameter expires. If the timeout expires before entering the lock, the method returns `false`. If the lock is already held by the current thread, the lock is entered again. The current thread should exit the lock as many times as it had entered the lock to fully exit the lock and allow other threads to enter the lock.
244+
245+
For more information, see the Remarks for <xref:System.Threading.Lock>.
246+
247+
]]></format>
248+
</remarks>
249+
<exception cref="System.Threading.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is less than <code>-1</code>.</exception>
250+
<exception cref="System.Threading.LockRecursionException">The lock has reached the limit of repeated enters by the current thread. The limit is implementation-defined and is intended to be high enough that it would not be reached in normal situations.</exception>
174251
</Docs>
175252
</Member>
176253
<Member MemberName="TryEnter">
@@ -192,10 +269,22 @@
192269
<Parameter Name="timeout" Type="System.TimeSpan" />
193270
</Parameters>
194271
<Docs>
195-
<param name="timeout">To be added.</param>
196-
<summary>To be added.</summary>
197-
<returns>To be added.</returns>
198-
<remarks>To be added.</remarks>
272+
<param name="timeout">A <see cref="T:System.TimeSpan" /> that represents the number of milliseconds to wait until the lock can be entered. A value that represents <see cref="F:System.Threading.Timeout.Infinite" /> (<code>-1</code>) milliseconds specifies to wait indefinitely, and a value that represents <code>0</code> milliseconds specifies to not wait.</param>
273+
<summary>Tries to enter the lock, waiting if necessary until the lock can be entered or until the specified timeout expires.</summary>
274+
<returns><see langword="true" /> if the lock was entered by the current thread; otherwise, <see langword="false" />.</returns>
275+
<remarks>
276+
<format type="text/markdown"><![CDATA[
277+
278+
## Remarks
279+
280+
When the method returns `true`, the current thread would be the only thread that holds the lock. If the lock cannot be entered immediately, the method waits until the lock can be entered or until the specified `timeout` expires. If the timeout expires before entering the lock, the method returns `false`. If the lock is already held by the current thread, the lock is entered again. The current thread should exit the lock as many times as it had entered the lock to fully exit the lock and allow other threads to enter the lock.
281+
282+
For more information, see the Remarks for <xref:System.Threading.Lock>.
283+
284+
]]></format>
285+
</remarks>
286+
<exception cref="System.Threading.ArgumentOutOfRangeException"><paramref name="timeout"/>, after its conversion to an integer millisecond value, represents a value that is less than <code>-1</code> milliseconds or greater than <see cref="int.MaxValue"/> milliseconds.</exception>
287+
<exception cref="System.Threading.LockRecursionException">The lock has reached the limit of repeated enters by the current thread. The limit is implementation-defined and is intended to be high enough that it would not be reached in normal situations.</exception>
199288
</Docs>
200289
</Member>
201290
</Members>

0 commit comments

Comments
 (0)