Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork0
Library of Types and Property Wrappers designed to provide Thread Safety simply and quickly for any Swift project
License
Flowduino/ThreadSafeSwift
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Collection of Property Wrappers and other Types explicitly designed to provide quick, simple, and efficient Thread-Safety in your Swift projects.
SelectFile ->Swift Packages ->Add Package Dependency and enterhttps://github.com/Flowduino/ThreadSafeSwift.git
You can useThreadSafeSwift as a Package Dependency in your own Packages'Package.swift file:
letpackage=Package( //... dependencies:[.package( url:"https://github.com/Flowduino/ThreadSafeSwift.git",.upToNextMajor(from:"1.1.0")),], //...)
From there, refer toThreadSafeSwift as a "target dependency" in any ofyour package's targets that need it.
targets:[.target( name:"YourLibrary", dependencies:["ThreadSafeSwift",], //...), //...]
You can then doimport ThreadSafeSwift in any code that requires it.
Here are some quick and easy usage examples for the features provided byThreadSafeSwift:
You can use theThreadSafeSemaphore Property Wrapper to encapsulate any Value Type behind a Thread-SafeDispatchSemaphore.This is extremely easy for most types:
@ThreadSafeSemaphorevarmyInt:Int
Further, you can access the underlyingDispatchSemaphore directly, which is useful where you need to acquire the Lock for multiple operations that must performedAtomically:
@ThreadSafeSemaphorevarmyInts:[Int]//...func incrementEveryIntegerByOne(){ _myInts.lock.wait()for(index,val)in myInts.enumerated(){myInts[index]= val+1} _myInts.lock.signal()}
Of course, for Arrays, you really should try to minimize the number of get/set operations required, and the duration throughout which theDispatchSemaphore is locked:
@ThreadSafeSemaphorevarmyInts:[Int]//...func incrementEveryIntegerByOne(){varvalues= myInts // This would marshal the `DispatchSemaphore` and return a copy of the Array, then release the `DispatchSemaphore`for(index,val)in values.enumerated(){myInts[index]= val+1} myInts= values // This would marshal the `DispatchSempahore` and replace the entire Array with our modified one, then release the `DispatchSemaphore`}
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 theDispatchSemaphore lock against the value for the duration of these operations.To facilitate this, we can use thewithLock method against anyThreadSafeSemaphore decorated variable:
@ThreadSafeSemaphorevarmyInts:[Int]=[0,1,2,3,4,5,6,7,8,9]
Here we have aThreadSafeSemaphore decorated Array of Integers.
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 usingwithLock:
func incrementEachValueByOne(){ _myInts.withLock{ valueinfor(index, val)in value.enumerated(){value[index]= val+1}}}
Please pay attention to the preceeding underscore_ beforemyInts when invoking thewithLock method. This is important, as the underscore instructs Swift to reference the Property Decorator rather than itswrappedValue.
IMPORTANT NOTE: - You mustnot 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 againstvalue as defined within the scope of the Closure itself (as shown above).
So, as you can see, we can now encapsulatecomplex types with the@ThreadSafeSemaphore decorator and operate against all of its members within the safety of theDispatchSemaphore lock.
ThreadSafeSemaphore.withTryLock - Execute a Closure while retaining the Lock IF we can acquire it, otherwise execute a failure Closure
As withThreadSafeSemaphore.withLock (explained above), we may need to perform one or more operations within the context of theDispatchSemaphore onlyif it is possible to obtain theDispatchSemaphore Lock at that time. Where it is not possible to acquire theDispatchSemaphore lock at that moment, we may want to execute another piece of conditional code.
We can do that easily:
@ThreadSafeSemaphorevarmyInts:[Int]=[0,1,2,3,4,5,6,7,8,9]
Again, we declare our@ThreadSafeSemaphore decorated Variable.
Now let's see how we would usewithTryLock againstmyInts:
func incrementEachValueByOne(){ _myInts.withTryLock{ valuein // If we got the Lockfor(index, val)in value.enumerated(){value[index]= val+1}} _:{ // If we couldn't get the Lockprint("We wanted to acquire the Lock, but couldn't... so we can do something else instead!")}}
IMPORTANT NOTE: - You mustnot reference the variable itself (in the above example,myInts) within the scope of theeither Closure. If you do, the Thread will lock at that command and proceed no further. All mutations to the value must be performed againstvalue as defined within the scope of the Closure itself (as shown above).
TheseConditional Closures are extremely useful where your code needs to progress down a different execution path depending on whether it can or cannot acquire theDispatchSemaphore lock at the point of execution.
TIP: - I use this very approach to implement "Revolving Door Locks" for Collections. A feature that will be added to this library very soon!
ThreadSafeSwift is available under the MIT license. See theLICENSE file for more info.
About
Library of Types and Property Wrappers designed to provide Thread Safety simply and quickly for any Swift project
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.