4 ms·
My sibling comment is explaining this correctly but maybe using a bit too much Rust jargon for the uninitiated. Put simply: How would two thread get access to
by j-pb 2y ago
My sibling comment is explaining this correctly but maybe using a bit too much Rust jargon for the uninitiated.
Put simply: How would two thread get access to the same account at the same time? There would be a point in time where the object would have to be split to end up in both of them, which would be invalid.
This is why you see things like this in rust
let x = 5;
let thread = thread::spawn(move || { // <- important bit
println!("{}", x);
});
println!("{}", x); // <- this would fail
The thread uses a 'move closure', which takes ownership of all values from the outside scope that are used inside its body.
Note that a value needs to be marked as `Send` so that it can pass across threads, but most types are.
That's what makes it so powerful. You know that any value you have in any variable, is only in that variable and nowhere else in the "world". Sure that value can be `Copy` and automatically copied, but that's still a new value.
Your value can be `Sync` which means that a reference of it is `Send`, but you're not splitting up the value, you're creating and tracking a new reference value that is then send across the thread boundary.
- mrkeen 2y agoRight, I was thrown by the real world terms. The ownership system (and syntax) isn't doing anything about a blocked account, it's just preventing a use-after-move, which has nothing to do with this-thread-blocks, that-thread-transfers. (This is also why I walk past Erlang. Such emphasis on share-nothing prevents an account from being shared by a customer and a bank manager.) So, what is the actual solution for a thread asking if any other thread has blocked(acct1), so that transfer() can proceed or be rolled back?
- vlovich123 2y agoPinning objects to single threads and message passing and/or transactions systems. Transactions typically aren’t seen at the language level and are more common within database systems. Typically a thread-per-core design with objects pinned to cores randomly would scale the best even for transactions; you can develop hotspots but in practice you win a lot more by not having to synchronize unless you’re doing cross-object transactions. I’m not aware of any language that provides these kinds of guarantees statically or what that would even look like. You’re asking for a lot vs where the cutting state of language design is.
- j-pb 2y agoYeah, the idea in the above code is that you can't do anything with an account so long as it's placed in the "blocked" set, because that means that it's effectively taken out of circulation for other operations. The way I solve situations like this is, by making sure that all accounts are moved to the same thread for a short period of time, which then handles the transaction. Which I find a lot easier to think about. It's essentially sharding by account and flexibly moving the shards into the same single writer context. But if you want to do things the "old fashioned way" Rust provides plenty of classical synchronisation primitives like `Mutex` or `RwLock`. You can also combine both approaches, e.g. have a single Mutex<AccountPool> that you can check out accounts from.