当前位置:网站首页>[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
Mutex
Inside :let app = Arc::new(FernEmpireApp { // Create the entire application , Distributed on the heap ... waiting_list: Mutex::new(vec![]), ... });
Arc
It is convenient to share data across threads .Mutex
It 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 ,
guard
After 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). Mutex
The mutex , Provide proprietary access to datamut
Access right , Even if many threads are rightMutex
Own 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(); // Deadlock
Using 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
Mutex
I was surprised , that Rust Will
Mutex
Mark as poisoned .
- Later, I want to lock the contaminated
Mutex
All 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
mpsc
Channel sharing succeeded .An exceptional way to bypass this limitation : It can be for
Receiver
Add 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
lock
Method to read and write data .The read-write lock uses
read
andwrite
There are two ways to read and write data .RwLock::write
Method : AndMutex::lock
similar , Are waiting to get proprietary information about protected datamut
visit .RwLock::read
Method provides nonmut
visit , 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
FernEmpireApp
Program :Create a structure to save configuration information , And by the
RwLock
Protect .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 forAppConfig
Non -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::Condvar
Type implements conditional variables .- its
.wait()
Method can block some threads to call its.notify_all()
.
Mutex
AndCondvar
There is a direct connection : The conditional variable always represents by someMutex
Protected data or true or false conditions .
17.3.10 - Type of atom
std::sync::atomio
The module contains the atomic types used in lock free concurrent programming .
AtomicIsize
andAtomicUsize
: Is a shared integer type , Corresponding to single threadisize
andusize
type .AtomicBool
: It's a sharedbool
value .AtomicPtr<T>
: Is an unsafe pointer type*mut T
Shared 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
AtomicBool
To 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
、RwLock
You can useself
The 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_staic
Package to achieve .
See 《Rust Programming 》( Jim - Brandy 、 Jason, - By orendov , Translated by lisongfeng ) Chapter 19
Original address
边栏推荐
- 【云原生】微服务之Feign自定义配置的记录
- Codeforces Round #716 (Div. 2) D. Cut and Stick
- Appium自动化测试基础 — Appium测试环境搭建总结
- [jailhouse article] performance measurements for hypervisors on embedded ARM processors
- Data visualization chart summary (II)
- Individual game 12
- Sword finger offer 53 - I. find the number I in the sorted array
- Annotation and reflection
- 2022年貴州省職業院校技能大賽中職組網絡安全賽項規程
- leetcode-6110:网格图中递增路径的数目
猜你喜欢
Sword finger offer 35 Replication of complex linked list
redis发布订阅命令行实现
6. Logistic model
1.15 - 输入输出系统
【Jailhouse 文章】Jailhouse Hypervisor
Implement an iterative stack
AtCoder Grand Contest 013 E - Placing Squares
Sword finger offer 06 Print linked list from beginning to end
【实战技能】如何做好技术培训?
CF1634E Fair Share
随机推荐
2020ccpc Qinhuangdao J - Kingdom's power
Individual game 12
CCPC Weihai 2021m eight hundred and ten thousand nine hundred and seventy-five
[article de jailhouse] jailhouse hypervisor
CF1634E Fair Share
The sum of the unique elements of the daily question
AtCoder Grand Contest 013 E - Placing Squares
QT判断界面当前点击的按钮和当前鼠标坐标
1.15 - 输入输出系统
Brief introduction to tcp/ip protocol stack
【Rust 笔记】16-输入与输出(上)
【Jailhouse 文章】Jailhouse Hypervisor
Dichotomy, discretization, etc
wordpress切换页面,域名变回了IP地址
Spark中groupByKey() 和 reduceByKey() 和combineByKey()
884. Uncommon words in two sentences
Personal developed penetration testing tool Satania v1.2 update
1.14 - 流水线
从Dijkstra的图灵奖演讲论科技创业者特点
[cloud native] record of feign custom configuration of microservices