You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To avoid concurrency bugs in your multithreaded program, always follow an appropriate locking discipline and use SAL annotations.
35
35
36
-
Concurrency bugs are notoriously hard to reproduce, diagnose, and debug because they're non-deterministic. Reasoning about thread interleaving is difficult at best, and becomes impractical when you're designing a body of code that has more than a few threads. Therefore, it's good practice to follow a locking discipline in your multithreaded programs. For example, obeying a lock order while acquiring multiple locks helps avoid deadlocks, and acquiring the proper guarding lock before accessing a shared resource helps prevent race conditions.
36
+
Concurrency bugs are notoriously hard to reproduce, diagnose, and debug because they're nondeterministic. Reasoning about thread interleaving is difficult at best, and becomes impractical when you're designing a body of code that has more than a few threads. Therefore, it's good practice to follow a locking discipline in your multithreaded programs. For example, obeying a lock order while acquiring multiple locks helps avoid deadlocks, and acquiring the proper guarding lock before accessing a shared resource helps prevent race conditions.
37
37
38
-
Unfortunately, seemingly simple locking rules can be surprisingly hard to follow in practice. A fundamental limitation in today's programming languages and compilers is that they do not directly support the specification and analysis of concurrency requirements. Programmers have to rely on informal code comments to express their intentions about how they use locks.
38
+
Unfortunately, seemingly simple locking rules can be surprisingly hard to follow in practice. A fundamental limitation in today's programming languages and compilers is that they don't directly support the specification and analysis of concurrency requirements. Programmers have to rely on informal code comments to express their intentions about how they use locks.
39
39
40
40
Concurrency SAL annotations are designed to help you specify locking side effects, locking responsibility, data guardianship, lock order hierarchy, and other expected locking behavior. By making implicit rules explicit, SAL concurrency annotations provide a consistent way for you to document how your code uses locking rules. Concurrency annotations also enhance the ability of code analysis tools to find race conditions, deadlocks, mismatched synchronization operations, and other subtle concurrency errors.
41
41
@@ -64,10 +64,10 @@ The following table lists the locking annotations.
64
64
|`_Acquires_nonreentrant_lock_(expr)`|The lock that's named by `expr` is acquired. An error is reported if the lock is already held.|
65
65
|`_Acquires_shared_lock_(expr)`|Annotates a function and indicates that in post state the function increments by one the shared lock count of the lock object that's named by `expr`.|
66
66
|`_Create_lock_level_(name)`|A statement that declares the symbol `name` to be a lock level so that it may be used in the annotations `_Has_Lock_level_` and `_Lock_level_order_`.|
67
-
|`_Has_lock_kind_(kind)`|Annotates any object to refine the type information of a resource object. Sometimes a common type is used for different kinds of resources and the overloaded type isn't sufficient to distinguish the semantic requirements among various resources. Here's a list of pre-defined`kind` parameters:<br /><br /> `_Lock_kind_mutex_`<br /> Lock kind ID for mutexes.<br /><br /> `_Lock_kind_event_`<br /> Lock kind ID for events.<br /><br /> `_Lock_kind_semaphore_`<br /> Lock kind ID for semaphores.<br /><br /> `_Lock_kind_spin_lock_`<br /> Lock kind ID for spin locks.<br /><br /> `_Lock_kind_critical_section_`<br /> Lock kind ID for critical sections.|
67
+
|`_Has_lock_kind_(kind)`|Annotates any object to refine the type information of a resource object. Sometimes a common type is used for different kinds of resources and the overloaded type isn't sufficient to distinguish the semantic requirements among various resources. Here's a list of predefined`kind` parameters:<br /><br /> `_Lock_kind_mutex_`<br /> Lock kind ID for mutexes.<br /><br /> `_Lock_kind_event_`<br /> Lock kind ID for events.<br /><br /> `_Lock_kind_semaphore_`<br /> Lock kind ID for semaphores.<br /><br /> `_Lock_kind_spin_lock_`<br /> Lock kind ID for spin locks.<br /><br /> `_Lock_kind_critical_section_`<br /> Lock kind ID for critical sections.|
68
68
|`_Has_lock_level_(name)`|Annotates a lock object and gives it the lock level of `name`.|
69
69
|`_Lock_level_order_(name1, name2)`|A statement that gives the lock ordering between `name1` and `name2`. Locks that have level `name1` must be acquired before locks that have level `name2`.|
70
-
|`_Post_same_lock_(expr1, expr2)`|Annotates a function and indicates that in post state the two locks, `expr1` and `expr2`, are treated as if they're the same lock object.|
70
+
|`_Post_same_lock_(dst, src)`|Annotates a function and indicates that in post state the two locks, `dst` and `src`, are treated as if they're the same lock object, by applying lock properties from `src` to `dst`.|
71
71
|`_Releases_exclusive_lock_(expr)`|Annotates a function and indicates that in post state the function decrements by one the exclusive lock count of the lock object that's named by `expr`.|
72
72
|`_Releases_lock_(expr)`|Annotates a function and indicates that in post state the function decrements by one the lock count of the lock object that's named by `expr`.|
73
73
|`_Releases_nonreentrant_lock_(expr)`|The lock that's named by `expr` is released. An error is reported if the lock isn't currently held.|
@@ -97,17 +97,17 @@ The following table lists the annotations for shared data access.
97
97
|----------------|-----------------|
98
98
|`_Guarded_by_(expr)`|Annotates a variable and indicates that whenever the variable is accessed, the lock count of the lock object that's named by `expr` is at least one.|
99
99
|`_Interlocked_`|Annotates a variable and is equivalent to `_Guarded_by_(_Global_interlock_)`.|
100
-
|`_Interlocked_operand_`|The annotated function parameter is the target operand of one of the various Interlocked functions. Those operands must have specific additional properties.|
100
+
|`_Interlocked_operand_`|The annotated function parameter is the target operand of one of the various Interlocked functions. Those operands must have other specific properties.|
101
101
|`_Write_guarded_by_(expr)`|Annotates a variable and indicates that whenever the variable is modified, the lock count of the lock object that's named by `expr` is at least one.|
102
102
103
103
## Smart Lock and RAII Annotations
104
104
105
-
Smart locks typically wrap native locks and manage their lifetime. The following table lists annotations that can be used with smart locks and RAII coding patterns with support for `move` semantics.
105
+
Smart locks typically wrap native locks and manage their lifetime. The following table lists annotations that can be used with smart locks and Resource Acquisition Is Initialization (RAII) coding patterns with support for `move` semantics.
106
106
107
107
|Annotation|Description|
108
108
|----------------|-----------------|
109
-
|`_Analysis_assume_smart_lock_acquired_(lock)`|Tells the analyzer to assume that a smart lock has been acquired. This annotation expects a reference lock type as its parameter.|
110
-
|`_Analysis_assume_smart_lock_released_(lock)`|Tells the analyzer to assume that a smart lock has been released. This annotation expects a reference lock type as its parameter.|
109
+
|`_Analysis_assume_smart_lock_acquired_(lock)`|Tells the analyzer to assume that a smart lock was acquired. This annotation expects a reference lock type as its parameter.|
110
+
|`_Analysis_assume_smart_lock_released_(lock)`|Tells the analyzer to assume that a smart lock was released. This annotation expects a reference lock type as its parameter.|
111
111
|`_Moves_lock_(target, source)`|Describes a `move constructor` operation, which transfers lock state from the `source` object to the `target`. The `target` is considered a newly constructed object, so any state it had before is lost and replaced by the `source` state. The `source` is also reset to a clean state with no lock counts or aliasing target, but aliases pointing to it remain unchanged.|
112
112
|`_Replaces_lock_(target, source)`|Describes `move assignment operator` semantics where the target lock is released before transferring the state from the source. You can regard it as a combination of `_Moves_lock_(target, source)` preceded by a `_Releases_lock_(target)`.|
113
113
|`_Swaps_locks_(left, right)`|Describes the standard `swap` behavior, which assumes that objects `left` and `right` exchange their state. The state exchanged includes lock count and aliasing target, if present. Aliases that point to the `left` and `right` objects remain unchanged.|
0 commit comments