Skip to content

Add warnings and guidance against using volatile keyword #47282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/csharp/language-reference/keywords/volatile.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ ms.assetid: 78089bc7-7b38-4cfd-9e49-87ac036af009

The `volatile` keyword indicates that a field might be modified by multiple threads that are executing at the same time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. Fields that are declared `volatile` are excluded from certain kinds of optimizations. There is no guarantee of a single total ordering of volatile writes as seen from all threads of execution. For more information, see the <xref:System.Threading.Volatile> class.

> [!CAUTION]
> The `volatile` keyword is often misunderstood and misused in multithreaded programming. In most scenarios, you should use safer and more reliable alternatives instead of `volatile`. Modern .NET provides better concurrency tools like the <xref:System.Threading.Interlocked> class, the [`lock`](../statements/lock.md) statement, or higher-level synchronization primitives. These alternatives provide clearer semantics and stronger guarantees than `volatile`. Consider using `volatile` only in rare, advanced scenarios where you fully understand its limitations and have verified it's the appropriate solution.

> [!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.

Expand All @@ -27,8 +30,21 @@ The `volatile` keyword can be applied to fields of these types:

Other types, including `double` and `long`, cannot be marked `volatile` because reads and writes to fields of those types cannot be guaranteed to be atomic. To protect multi-threaded access to those types of fields, use the <xref:System.Threading.Interlocked> class members or protect access using the [`lock`](../statements/lock.md) statement.

For most multithreaded scenarios, even with supported types, prefer using <xref:System.Threading.Interlocked> operations, [`lock`](../statements/lock.md) statements, or other synchronization primitives instead of `volatile`. These alternatives provide stronger guarantees and are less prone to subtle concurrency bugs.

The `volatile` keyword can only be applied to fields of a `class` or `struct`. Local variables cannot be declared `volatile`.

## Alternatives to volatile

In most cases, you should use one of these safer alternatives instead of `volatile`:

- **<xref:System.Threading.Interlocked> operations**: Provide atomic operations for numeric types and reference assignments. These are generally faster and provide stronger guarantees than `volatile`.
- **[`lock` statement](../statements/lock.md)**: Provides mutual exclusion and memory barriers. Use for protecting larger critical sections.
- **<xref:System.Threading.Volatile> class**: Provides explicit volatile read and write operations with clearer semantics than the `volatile` keyword.
- **Higher-level synchronization primitives**: Such as <xref:System.Threading.ReaderWriterLockSlim>, <xref:System.Threading.Semaphore>, or concurrent collections from <xref:System.Collections.Concurrent>.

The `volatile` keyword doesn't provide atomicity for operations other than assignment, doesn't prevent race conditions, and doesn't provide ordering guarantees for other memory operations. These limitations make it unsuitable for most concurrency scenarios.

## Example

The following example shows how to declare a public field variable as `volatile`.
Expand All @@ -52,3 +68,6 @@ With the `volatile` modifier added to the declaration of `_shouldStop` in place,
- [Modifiers](index.md)
- [lock statement](../statements/lock.md)
- <xref:System.Threading.Interlocked>
- <xref:System.Threading.Volatile>
- <xref:System.Collections.Concurrent>
- [Managed Threading](../../../standard/threading/managed-threading-basics.md)
Loading