From 16dc07c339db3102f3b3b4efd120f32dc5af3124 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Thu, 9 Sep 2021 17:37:12 -0700 Subject: [PATCH 1/2] Clarify/fix some threading API docs - Clarify terms used in `LazyThreadSafetyMode` field names. Relevant to https://github.com/dotnet/docs/issues/12214. - Clarify documentation of the `Volatile` class. Relevant to https://github.com/dotnet/docs/issues/24318. - Update docs for `Thread.VolatileRead` and `Thread.VolatileWrite`. Fixes https://github.com/dotnet/dotnet-api-docs/issues/2518. - Clarify something about `ManualResetEventSlim`'s perf benefit over `ManualResetEvent`. Fixes https://github.com/dotnet/dotnet-api-docs/issues/3323. --- xml/System.Threading/LazyThreadSafetyMode.xml | 4 +- xml/System.Threading/ManualResetEventSlim.xml | 4 +- xml/System.Threading/Thread.xml | 368 ++++-------------- xml/System.Threading/Volatile.xml | 59 +-- 4 files changed, 103 insertions(+), 332 deletions(-) diff --git a/xml/System.Threading/LazyThreadSafetyMode.xml b/xml/System.Threading/LazyThreadSafetyMode.xml index d29f39704bc..6fd64e0962a 100644 --- a/xml/System.Threading/LazyThreadSafetyMode.xml +++ b/xml/System.Threading/LazyThreadSafetyMode.xml @@ -104,7 +104,7 @@ 2 - Locks are used to ensure that only a single thread can initialize a instance in a thread-safe manner. If the initialization method (or the parameterless constructor, if there is no initialization method) uses locks internally, deadlocks can occur. If you use a constructor that specifies an initialization method ( parameter), and if that initialization method throws an exception (or fails to handle an exception) the first time you call the property, then the exception is cached and thrown again on subsequent calls to the property. If you use a constructor that does not specify an initialization method, exceptions that are thrown by the parameterless constructor for are not cached. In that case, a subsequent call to the property might successfully initialize the instance. If the initialization method recursively accesses the property of the instance, an is thrown. + Locks are used to ensure that only a single thread can initialize a instance in a thread-safe manner. Effectively, the initialization method is executed in a thread-safe manner (referred to as `Execution` in the field name), and `Publication` of the initialized value is also thread-safe in the sense that only one value may be published and used by all threads. If the initialization method (or the parameterless constructor, if there is no initialization method) uses locks internally, deadlocks can occur. If you use a constructor that specifies an initialization method ( parameter), and if that initialization method throws an exception (or fails to handle an exception) the first time you call the property, then the exception is cached and thrown again on subsequent calls to the property. If you use a constructor that does not specify an initialization method, exceptions that are thrown by the parameterless constructor for are not cached. In that case, a subsequent call to the property might successfully initialize the instance. If the initialization method recursively accesses the property of the instance, an is thrown. @@ -186,7 +186,7 @@ 1 - When multiple threads try to initialize a instance simultaneously, all threads are allowed to run the initialization method (or the parameterless constructor, if there is no initialization method). The first thread to complete initialization sets the value of the instance. That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of that were created by the competing threads are discarded. If the initialization method throws an exception on any thread, the exception is propagated out of the property on that thread. The exception is not cached. The value of the property remains , and subsequent calls to the property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the property of the instance, no exception is thrown. + When multiple threads try to initialize a instance simultaneously, all threads are allowed to run the initialization method (or the parameterless constructor, if there is no initialization method). The first thread to complete initialization sets the value of the instance (this is referred to as `Publication` in the field names). That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of that were created by the competing threads are discarded. Effectively, the publication of the initialized value is thread-safe in the sense that only one of the initialized values may be published and used by all threads. If the initialization method throws an exception on any thread, the exception is propagated out of the property on that thread. The exception is not cached. The value of the property remains , and subsequent calls to the property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the property of the instance, no exception is thrown. diff --git a/xml/System.Threading/ManualResetEventSlim.xml b/xml/System.Threading/ManualResetEventSlim.xml index 11cd496272f..b968ff6ba39 100644 --- a/xml/System.Threading/ManualResetEventSlim.xml +++ b/xml/System.Threading/ManualResetEventSlim.xml @@ -56,7 +56,9 @@ ## Remarks You can use this class for better performance than when wait times are expected to be very short, and when the event does not cross a process boundary. uses busy spinning for a short time while it waits for the event to become signaled. When wait times are short, spinning can be much less expensive than waiting by using wait handles. However, if the event does not become signaled within a certain period of time, resorts to a regular event handle wait. - +> [!NOTE] +> In .NET Core and .NET 5+, the default spin-waiting duration is very short, in the order of 10s of microseconds depending on platform and processor. If wait times are expected to be much longer than that, this class can still be used instead of (perhaps configured with less or no spin-waiting), but the performance benefit would likely be only marginal. + ## Examples The following example shows how to use a . diff --git a/xml/System.Threading/Thread.xml b/xml/System.Threading/Thread.xml index a1b153549b2..a450de52961 100644 --- a/xml/System.Threading/Thread.xml +++ b/xml/System.Threading/Thread.xml @@ -4178,7 +4178,7 @@ Unlike , which captures the c 4.0.0.0 - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. @@ -4217,22 +4217,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4274,22 +4265,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4331,22 +4313,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4388,22 +4361,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4445,22 +4409,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4502,22 +4457,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4566,22 +4512,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4629,22 +4566,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4686,22 +4614,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4749,22 +4668,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4812,22 +4722,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4875,22 +4776,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4938,22 +4830,13 @@ Unlike , which captures the c The field to be read. - Reads the value of a field. The value is the latest written by any processor in a computer, regardless of the number of processors or the state of processor cache. - The latest value written to the field by any processor. + Reads the value of a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. + The value that was read. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, obtains the very latest value written to a memory location by any processor. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -4966,7 +4849,7 @@ Unlike , which captures the c 4.0.0.0 - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. @@ -5007,21 +4890,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5065,21 +4939,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5123,21 +4988,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5181,21 +5037,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5239,21 +5086,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5297,21 +5135,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5363,21 +5192,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5427,21 +5247,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5485,21 +5296,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5549,21 +5351,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5613,21 +5406,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5677,21 +5461,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> @@ -5741,21 +5516,12 @@ Unlike , which captures the c The field to which the value is to be written. The value to be written. - Writes a value to a field immediately, so that the value is visible to all processors in the computer. + Writes a value to a field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. and are for special cases of synchronization. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide easier alternatives. - - On a multiprocessor system, ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches. - - Even on a uniprocessor system, and ensure that a value is read or written to memory, and not cached (for example, in a processor register). Thus, you can use them to synchronize access to a field that can be updated by another thread, or by hardware. - - Calling this method affects only a single memory access. To provide effective synchronization for a field, all access to the field must use or . - -> [!NOTE] -> In C#, using the `volatile` modifier on a field guarantees that all access to that field uses or . + and are legacy APIs and have been replaced by and . See the class for more information. ]]> diff --git a/xml/System.Threading/Volatile.xml b/xml/System.Threading/Volatile.xml index 86da47d0e35..556a5718d0e 100644 --- a/xml/System.Threading/Volatile.xml +++ b/xml/System.Threading/Volatile.xml @@ -40,7 +40,10 @@ [!NOTE] +> On a multiprocessor system, a volatile read operation does not guarantee to obtain the latest value written to that memory location by any processor. Similarly, a volatile write operation does not guarantee that the value written would be immediately visible to other processors. > [!NOTE] > On a uniprocessor system, volatile reads and writes ensure that a value is read or written to memory and not cached (for example, in a processor register). Thus, you can use these operations to synchronize access to a field that can be updated by another thread or by hardware. @@ -119,7 +122,7 @@ The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field to read. Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method. - The value that was read. This value is the latest written by any processor in the computer, regardless of the number of processors or the state of processor cache. + The value that was read. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The field where the value is written. - The value to write. The value is written immediately so that it is visible to all processors in the computer. + The value to write. Writes the specified value to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. The type of field to write. This must be a reference type, not a value type. The field where the object reference is written. - The object reference to write. The reference is written immediately so that it is visible to all processors in the computer. + The object reference to write. Writes the specified object reference to the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears before this method in the code, the processor cannot move it after this method. Date: Fri, 10 Sep 2021 19:27:35 -0700 Subject: [PATCH 2/2] Apply suggestions from code review Thank you! Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- xml/System.Threading/LazyThreadSafetyMode.xml | 4 ++-- xml/System.Threading/ManualResetEventSlim.xml | 2 +- xml/System.Threading/Volatile.xml | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/xml/System.Threading/LazyThreadSafetyMode.xml b/xml/System.Threading/LazyThreadSafetyMode.xml index 6fd64e0962a..8c582702603 100644 --- a/xml/System.Threading/LazyThreadSafetyMode.xml +++ b/xml/System.Threading/LazyThreadSafetyMode.xml @@ -104,7 +104,7 @@ 2 - Locks are used to ensure that only a single thread can initialize a instance in a thread-safe manner. Effectively, the initialization method is executed in a thread-safe manner (referred to as `Execution` in the field name), and `Publication` of the initialized value is also thread-safe in the sense that only one value may be published and used by all threads. If the initialization method (or the parameterless constructor, if there is no initialization method) uses locks internally, deadlocks can occur. If you use a constructor that specifies an initialization method ( parameter), and if that initialization method throws an exception (or fails to handle an exception) the first time you call the property, then the exception is cached and thrown again on subsequent calls to the property. If you use a constructor that does not specify an initialization method, exceptions that are thrown by the parameterless constructor for are not cached. In that case, a subsequent call to the property might successfully initialize the instance. If the initialization method recursively accesses the property of the instance, an is thrown. + Locks are used to ensure that only a single thread can initialize a instance in a thread-safe manner. Effectively, the initialization method is executed in a thread-safe manner (referred to as `Execution` in the field name). `Publication` of the initialized value is also thread-safe in the sense that only one value may be published and used by all threads. If the initialization method (or the parameterless constructor, if there is no initialization method) uses locks internally, deadlocks can occur. If you use a constructor that specifies an initialization method ( parameter), and if that initialization method throws an exception (or fails to handle an exception) the first time you call the property, then the exception is cached and thrown again on subsequent calls to the property. If you use a constructor that does not specify an initialization method, exceptions that are thrown by the parameterless constructor for are not cached. In that case, a subsequent call to the property might successfully initialize the instance. If the initialization method recursively accesses the property of the instance, an is thrown. @@ -186,7 +186,7 @@ 1 - When multiple threads try to initialize a instance simultaneously, all threads are allowed to run the initialization method (or the parameterless constructor, if there is no initialization method). The first thread to complete initialization sets the value of the instance (this is referred to as `Publication` in the field names). That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of that were created by the competing threads are discarded. Effectively, the publication of the initialized value is thread-safe in the sense that only one of the initialized values may be published and used by all threads. If the initialization method throws an exception on any thread, the exception is propagated out of the property on that thread. The exception is not cached. The value of the property remains , and subsequent calls to the property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the property of the instance, no exception is thrown. + When multiple threads try to initialize a instance simultaneously, all threads are allowed to run the initialization method (or the parameterless constructor, if there is no initialization method). The first thread to complete initialization sets the value of the instance. This is referred to as `Publication` in the field names. That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of that were created by the competing threads are discarded. Effectively, the publication of the initialized value is thread-safe in the sense that only one of the initialized values may be published and used by all threads. If the initialization method throws an exception on any thread, the exception is propagated out of the property on that thread. The exception is not cached. The value of the property remains , and subsequent calls to the property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the property of the instance, no exception is thrown. diff --git a/xml/System.Threading/ManualResetEventSlim.xml b/xml/System.Threading/ManualResetEventSlim.xml index b968ff6ba39..2f6bc3bb9b5 100644 --- a/xml/System.Threading/ManualResetEventSlim.xml +++ b/xml/System.Threading/ManualResetEventSlim.xml @@ -57,7 +57,7 @@ You can use this class for better performance than when wait times are expected to be very short, and when the event does not cross a process boundary. uses busy spinning for a short time while it waits for the event to become signaled. When wait times are short, spinning can be much less expensive than waiting by using wait handles. However, if the event does not become signaled within a certain period of time, resorts to a regular event handle wait. > [!NOTE] -> In .NET Core and .NET 5+, the default spin-waiting duration is very short, in the order of 10s of microseconds depending on platform and processor. If wait times are expected to be much longer than that, this class can still be used instead of (perhaps configured with less or no spin-waiting), but the performance benefit would likely be only marginal. +> In .NET Core and .NET 5+, the default spin-waiting duration is short: on the order of 10s of microseconds, depending on platform and processor. If you expect wait times to be much longer than that, you can still use this class instead of (perhaps configured with less or no spin-waiting). However, the performance benefit would likely be only marginal. ## Examples diff --git a/xml/System.Threading/Volatile.xml b/xml/System.Threading/Volatile.xml index 556a5718d0e..7e71dd9ed10 100644 --- a/xml/System.Threading/Volatile.xml +++ b/xml/System.Threading/Volatile.xml @@ -43,10 +43,8 @@ On a multiprocessor system, due to performance optimizations in the compiler or processor, regular memory operations may appear to be reordered when multiple processors are operating on the same memory. Volatile memory operations prevent certain types of reordering with respect to the operation. A volatile write operation prevents earlier memory operations from being reordered to occur after the volatile write. A volatile read operation prevents later memory operations from being reordered to occur before the volatile read. These operations might involve memory barriers on some processors, which can affect performance. > [!NOTE] -> On a multiprocessor system, a volatile read operation does not guarantee to obtain the latest value written to that memory location by any processor. Similarly, a volatile write operation does not guarantee that the value written would be immediately visible to other processors. - -> [!NOTE] -> On a uniprocessor system, volatile reads and writes ensure that a value is read or written to memory and not cached (for example, in a processor register). Thus, you can use these operations to synchronize access to a field that can be updated by another thread or by hardware. +> - On a multiprocessor system, a volatile read operation is not guaranteed to obtain the latest value written to that memory location by any processor. Similarly, a volatile write operation does not guarantee that the value written would be immediately visible to other processors. +> - On a uniprocessor system, volatile reads and writes ensure that a value is read or written to memory and not cached (for example, in a processor register). Thus, you can use these operations to synchronize access to a field that can be updated by another thread or by hardware. Volatile memory operations are for special cases of synchronization, where normal locking is not an acceptable alternative. Under normal circumstances, the C# `lock` statement, the Visual Basic `SyncLock` statement, and the class provide the easiest and least error-prone way of synchronizing access to data, and the class provides a simple way to write lazy initialization code without directly using double-checked locking.