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
- Added `withLock` and `withTryLock` methods to `ThreadSafeSemaphore` property decorator.
- Added Unit Tests for the above
- Added examples for the above in the README.MD file.
myInts = values // This would marshal the `DispatchSempahore` and replace the entire Array with our modified one, then release the `DispatchSemaphore`
85
85
}
86
86
```
87
+
88
+
### `ThreadSafeSemaphore.withLock` - Execute a Closure while retaining the Lock
89
+
Often, it is necessary to perform more than one operation on a Value... and when you need to do this, you'll want to ensure that you retain the `DispatchSemaphore` lock against the value for the duration of these operations.
90
+
To facilitate this, we can use the `withLock` method against any `ThreadSafeSemaphore` decorated variable:
Here we have a `ThreadSafeSemaphore` decorated Array of Integers.
95
+
96
+
If we want to perform any number of operations against any number of values within this Array, we can now do so in a thread-safe manner using `withLock`:
97
+
```swift
98
+
funcincrementEachValueByOne() {
99
+
_myInts.withLock { value in
100
+
for (index, val) in value.enumerated() {
101
+
value[index] = val +1
102
+
}
103
+
}
104
+
}
105
+
```
106
+
Please pay attention to the preceeding underscore `_` before `myInts` when invoking the `withLock` method. This is important, as the underscore instructs Swift to reference the Property Decorator rather than its `wrappedValue`.
107
+
108
+
**IMPORTANT NOTE:** - You must *not* reference the variable itself (in the above example, `myInts`) within the scope of the Closure. If you do, the Thread will lock at that command and proceed no further. All mutations to the value must be performed against `value` as defined within the scope of the Closure itself (as shown above).
109
+
110
+
So, as you can see, we can now encapsulate *complex types* with the `@ThreadSafeSemaphore` decorator and operate against all of its members within the safety of the `DispatchSemaphore` lock.
111
+
112
+
### `ThreadSafeSemaphore.withTryLock` - Execute a Closure while retaining the Lock IF we can acquire it, otherwise execute a failure Closure
113
+
As with `ThreadSafeSemaphore.withLock` (explained above), we may need to perform one or more operations within the context of the `DispatchSemaphore` only *if* it is possible to obtain the `DispatchSemaphore` Lock at that time. Where it is not possible to acquire the `DispatchSemaphore` lock at that moment, we may want to execute another piece of conditional code.
Again, we declare our `@ThreadSafeSemaphore` decorated Variable.
120
+
121
+
Now let's see how we would use `withTryLock` against `myInts`:
122
+
```swift
123
+
funcincrementEachValueByOne() {
124
+
_myInts.withTryLock { value in
125
+
// If we got the Lock
126
+
for (index, val) in value.enumerated() {
127
+
value[index] = val +1
128
+
}
129
+
} _: {
130
+
// If we couldn't get the Lock
131
+
print("We wanted to acquire the Lock, but couldn't... so we can do something else instead!")
132
+
}
133
+
}
134
+
```
135
+
**IMPORTANT NOTE:** - You must *not* reference the variable itself (in the above example, `myInts`) within the scope of the *either* Closure. If you do, the Thread will lock at that command and proceed no further. All mutations to the value must be performed against `value` as defined within the scope of the Closure itself (as shown above).
136
+
137
+
These *Conditional Closures* are extremely useful where your code needs to progress down a different execution path depending on whether it can or cannot acquire the `DispatchSemaphore` lock at the point of execution.
138
+
139
+
**TIP:** - I use this very approach to implement "Revolving Door Locks" for Collections. A feature that will be added to this library very soon!
140
+
87
141
## License
88
142
89
143
`ThreadSafeSwift` is available under the MIT license. See the [LICENSE file](./LICENSE) for more info.
Copy file name to clipboardexpand all lines: Sources/ThreadSafeSwift/ThreadSafeSemaphore.swift
+28-1
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ import Foundation
10
10
/**
11
11
Enforces a `DispatchSemaphore` Lock against the given Value Type to ensure single-threaded access.
12
12
- Author: Simon J. Stuart
13
-
- Version: 1.0
13
+
- Version: 1.1.0
14
14
*/
15
15
@propertyWrapper
16
16
publicstructThreadSafeSemaphore<T>{
@@ -31,6 +31,33 @@ public struct ThreadSafeSemaphore<T> {
31
31
}
32
32
}
33
33
34
+
/**
35
+
Invokes your Closure within the confines of the `DispatchSemaphore` Lock (ensuring Mutually-Exclusive Access to your Value for the duration of execution)
36
+
- Parameters:
37
+
- code: The code you want to execute while the Lock is engaged.
Attempts to engage the `DispatchSemaphore` and, if successful, will invoke the Closure you provide to the `onLock` Closure. Otherwise, invokes the code you provide to the `onCannotLock` Closure.
47
+
- Parameters:
48
+
- onLock: The code to execute if the `DispatchSemaphore` can be acquired for mutually-exclusive access.
49
+
- onCannotLock: The code to execute if the `DispatchSemaphore` is currently locked by another Thread.
0 commit comments