当前位置:网站首页>[rust notes] 17 concurrent (Part 2)
[rust notes] 17 concurrent (Part 2)
2022-07-05 06:05:00 【phial03】
17.3 - Share modifiable state
17.3.1 - The mutex
The mutex ( Or lock ): Used to force multiple threads to access specific data in turn .
C++ Implementation example of mutual exclusion of :
void FernEngine::JoinWaitingList(PlayerId player) { mutex.Acquire(); // A critical region (critical section): Start waitingList.push_back(player); // If the waiting player meets the conditions, start the game if (waitingList.length() >= GAME_SIZE) { vector<PlayerId> players; waitingList.swap(players); StartGame(players); } mutex.Release(); // A critical region (critical section): end }The role of mutexes :
- Prevent data contention , Avoid multiple threads reading and writing the same block of memory concurrently .
- Prevent the operations of different threads from interleaving .
- Mutexes support invariance (invariant) Programming , The protected data is initialized by the performer , Maintained by each critical zone .
17.3.2-Mutex<T>
Rust The protected data in is stored in
MutexInside :let app = Arc::new(FernEmpireApp { // Create the entire application , Distributed on the heap ... waiting_list: Mutex::new(vec![]), ... });ArcIt is convenient to share data across threads .MutexIt is convenient to share modifiable data across threads .
give an example : Use mutex
impl FernEmpireApp { fn join_waiting_list(&self, player: PlayerId) { let mut guard = self.waiting_list.lock().unwrap(); guard.push(player); if guard.len() == GAME_SIZE { let players = guard.split_off(0); self.start_game(players); } } }The only way to get the data of the mutex is to call
.lock()Method .At the end of the jam ,
guardAfter being cleared , The lock will also be released . But it can also be removed manually :if guard.len() == GAME_SIZE { let players = guard.split_off(0); drop(guard); self.start_game(players); }
17.3.3-mut And Mutex
mut: Means proprietary 、 Exclusive access (exclusive access).- Not
mut: Means shared access (shared access). MutexThe mutex , Provide proprietary access to datamutAccess right , Even if many threads are rightMutexOwn sharing ( Notmut) Access right .- Rust Compiler at compile time , Proprietary access can be dynamically controlled through the type system .
17.3.4 - The problem of mutex
- Only rely on “ Parallel bifurcation — Merge ” The procedure is deterministic , It's impossible to deadlock .
- Procedures that specifically use channels to achieve pipeline operations are also deterministic , Although the time of message transmission may be different , But it will not affect the output .
- Data contention : Concurrent reading of the same block of memory by multiple threads leads to meaningless results . Safe Rust Code does not trigger data contention .
- There may be a problem with mutexes :
- Effective Rust There will be no data contention in the program , But there may still be race conditions (race condition), That is, the program behavior depends on the execution time of the thread , Therefore, the results of each run may be different . Using mutexes in an unstructured way can lead to race conditions .
- Shared modifiable state will affect program design . Channels can be used as abstract boundaries in code . Mutexes encourage the addition of a method to solve the problem , May cause code entanglement , Difficult to peel off .
- The implementation of mutex is more complex .
- Use structured programming whenever possible , Use mutexes when necessary
Mutex.
17.3.5 - Deadlock
Threads may cause deadlocks when trying to read locks they already hold .
let mut guard1 = self.waiting_list.lock().unwrap(); let mut guard2 = self.waiting_list.lock().unwrap(); // DeadlockUsing channels can also lead to deadlocks . For example, two threads block each other , Each waits to receive a message from the other .
17.3.6 - Poisoned mutex
If the thread is holding
MutexI was surprised , that Rust Will
MutexMark as poisoned .
- Later, I want to lock the contaminated
MutexAll attempts will get a wrong result . .unwrap()Call to tell Rust In this case, be surprised , Propagate the surprise of other threads to the current thread .- Surprised threads ensure that the rest of the program is in a safe state .
- Later, I want to lock the contaminated
Rust Poison this mutex to prevent other threads from inadvertently doing the same .
- In the case of complete mutual exclusion , It can lock the poisoned mutex , Access the data in it at the same time .
- See
PoisonError::into_inner().
17.3.7 - Multi consumer channels using mutexes
There is only one channel
Receiver.No thread pool can have multiple threads using one
mpscChannel sharing succeeded .An exceptional way to bypass this limitation : It can be for
ReceiverAdd oneMutex, Then share .pub mod shared_channel { use std::sync::{ Arc, Mutex}; use std::sync::mpsc::{ channel, Sender, Receiver}; /// Yes Receiver Thread safe encapsulation #[derive(Clone)] pub struct SharedReceiver<T>(Arc<Mutex<Receiver<T>>>); // Arc<Mutex<Receiver<T>>> Is a nested generic impl <T> Iterator for SharedReceiver<T> { type Item = T; /// Get the next item from the encapsulated recipient fn next(&mut self) -> Option<T> { let guard = self.0.lock().unwrap(); guard.recv().ok() } } /// Create a new channel , Its recipients can share across threads . /// Return a sender and a receiver , And stdlib Of channel() similar . /// Sometimes it can be used directly instead of it . pub fn shared_channel<T>() -> (Sender<T>, SharedReceiver<T>) { let (sender, receiver) = channel(); (sender, SharedReceiver(Arc::new(Mutex::new(receiver)))) } }
17.3.8 - Read write lock and RwLock<T>
Mutex uses
lockMethod to read and write data .The read-write lock uses
readandwriteThere are two ways to read and write data .RwLock::writeMethod : AndMutex::locksimilar , Are waiting to get proprietary information about protected datamutvisit .RwLock::readMethod provides nonmutvisit , There's almost no need to wait , Because multiple threads can read data safely at the same time .
The difference between mutex and read-write lock :
- At any given moment , Protected data can only have one reader or writer .
- When a read-write lock is used , There can be one writer or multiple readers , Be similar to Rust quote .
- It is preferred to use read-write lock , Not mutexes .
Optimize the above
FernEmpireAppProgram :Create a structure to save configuration information , And by the
RwLockProtect .use std::sync::RwLock; struct FernEmpireApp { ... config: RwLock<AppConfig>, ... }The method of reading this configuration can use
RwLock::read():fn mushrooms_enabled(&self) -> bool { let config_guard = self.config.read().unwrap(); config_guard.mushrooms_enabled }How to reload this configuration , Then use
RwLock::write():fn reload_config(&self) -> io::Result<()> { let new_config = AppConfig::load()?; let mut config_guard = self.config.write().unwrap(); *config_guard = new_config; Ok(()) }self.config.read()Return to a guard , Can provide forAppConfigNon -mut( Sharing ) visit ;self.config.write()Return a different type of guard , Can providemut( Proprietary ) visit .
17.3.9 - Condition variables, (Condvar)
A thread often needs to wait for a condition to become
true:
- During server shutdown , The main thread may need to wait for all other threads to exit completely .
- When the worker thread is idle , You need to wait for the data to be processed .
- Threads that implement distributed consensus protocols , You need to wait for enough peer threads to respond .
For conditions that require waiting , There will be convenient blockage API, without , Then you can use conditional variables (condition variable) To build your own API.
std::sync::CondvarType implements conditional variables .- its
.wait()Method can block some threads to call its.notify_all().
MutexAndCondvarThere is a direct connection : The conditional variable always represents by someMutexProtected data or true or false conditions .
17.3.10 - Type of atom
std::sync::atomioThe module contains the atomic types used in lock free concurrent programming .
AtomicIsizeandAtomicUsize: Is a shared integer type , Corresponding to single threadisizeandusizetype .AtomicBool: It's a sharedboolvalue .AtomicPtr<T>: Is an unsafe pointer type*mut TShared value of .
The simplest application of atoms is to cancel operations . Suppose there is a thread performing some time-consuming computation of any , Such as rendering video , We hope to cancel this operation asynchronously . Then you can use a shared
AtomicBoolTo achieve . Render every pixel , Threads will call.load()Method to check the value of the cancel flag .Atomic operations never use system calls . Loading and storage will be compiled into a CPU Instructions .
atom 、
Mutex、RwLockYou can useselfThe shared reference of is a parameter . They can also be used as simple global variables .
17.3.11 - Global variables
- For global variables : Thread safety must be guaranteed in some way . Static variables must be both
Sync, Right and wrong againmut. - Static initializers cannot call functions . have access to
lazy_staicPackage to achieve .
See 《Rust Programming 》( Jim - Brandy 、 Jason, - By orendov , Translated by lisongfeng ) Chapter 19
Original address
边栏推荐
猜你喜欢

Introduction et expérience de wazuh open source host Security Solution

Smart construction site "hydropower energy consumption online monitoring system"

LeetCode 0107.二叉树的层序遍历II - 另一种方法

Fried chicken nuggets and fifa22

1.15 - 输入输出系统

wordpress切换页面,域名变回了IP地址

Personal developed penetration testing tool Satania v1.2 update

Sword finger offer 35 Replication of complex linked list

2017 USP Try-outs C. Coprimes

Appium自动化测试基础 — Appium测试环境搭建总结
随机推荐
927. 三等分 模拟
Common optimization methods
API related to TCP connection
Sword finger offer 05 Replace spaces
Spark中groupByKey() 和 reduceByKey() 和combineByKey()
Configuration and startup of kubedm series-02-kubelet
【实战技能】如何做好技术培训?
js快速将json数据转换为url参数
多屏电脑截屏会把多屏连着截下来,而不是只截当前屏
LVS简介【暂未完成(半成品)】
CCPC Weihai 2021m eight hundred and ten thousand nine hundred and seventy-five
【Rust 笔记】14-集合(下)
QQ computer version cancels escape character input expression
liunx启动redis
【Jailhouse 文章】Performance measurements for hypervisors on embedded ARM processors
AtCoder Grand Contest 013 E - Placing Squares
shared_ Repeated release heap object of PTR hidden danger
【Rust 笔记】17-并发(上)
Data visualization chart summary (II)
leetcode-31:下一个排列