Scott Steinbeck
11/12/2022, 9:14 PMbdw429s
11/12/2022, 9:15 PMbdw429s
11/12/2022, 9:16 PMbdw429s
11/12/2022, 9:16 PMbdw429s
11/12/2022, 9:17 PMbdw429s
11/12/2022, 9:22 PMfunction transferFunds( numeric amount ) {
lock name="ledger" timeout=10 type="exclusive" {
savings.debit( amount );
<http://log.info|log.info>( 'Transferring funds...' )
checking.deposit( amount );
}
}
...
function getChecking() {
lock name="ledger" timeout=10 type="readonly" {
checking.getTotal();
}
}
function getSavings() {
lock name="ledger" timeout=10 type="readonly" {
savings.getTotal();
}
}
Imagine if one thread was in the middle of trasnferring $100 from savings to checking, while another thread called the getChecking() and getSavings() methods at the exact same time and the numbers didn't line up. So long as every access to the ledger used a readonly lock and all modifications used an exclusive lock, you could ensure consistency between the two values.bdw429s
11/12/2022, 9:24 PMvar++
or var--
which isn't atomic/threadsafe, lol)Scott Steinbeck
11/12/2022, 9:28 PMScott Steinbeck
11/12/2022, 9:28 PMbdw429s
11/12/2022, 9:28 PMbdw429s
11/12/2022, 9:28 PMthrowontimeout
bdw429s
11/12/2022, 9:29 PMbdw429s
11/12/2022, 9:29 PMbdw429s
11/12/2022, 9:29 PMAdam Cameron
doStuff() {
someSharedScopeVar = somePointInTimeValue
// calculation based on the value someSharedScopeVar was set to in this thread
// more calcs
// and more
return someResultBasedOnThoseCalcs
}
If the bottom line is intrinsically connected to the starting value, then you probably won't want a second thread coming in whilst a first thread is in the middle of finalising its result; so one locks all that to make sure only only thread at a time will run that code.
This might not be initialisation code, it might be fine for the code to run as often as needs-must, but it's important it only runs once at a time. One needs the code to be atomic.
Of course there will also quite possibly be strategies to mitigate this... one should avoid having to write code like this if at all possible, but sometimes it's unavoidable / the right way to do things.
Also note for this example I use someSharedScopeVar
, but it could be any datum that is present in a way that multiple threads could access it whilst it's being worked on. It might be a row in a DB or a file or whatever. The point is if there are multi-statement operations that need to be atomic; they need to be locked.
It's probably beneficial to think outside CFML specifically for this, and read up on synchronisation and race conditions in general. They're present anywhere there's code, so there will be more learned writing out there than you'll get from some CFML chat app 😉