当前位置:网站首页>[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
边栏推荐
- 【Jailhouse 文章】Jailhouse Hypervisor
- Full Permutation Code (recursive writing)
- 1040 Longest Symmetric String
- Personal developed penetration testing tool Satania v1.2 update
- In this indifferent world, light crying
- The sum of the unique elements of the daily question
- LVS简介【暂未完成(半成品)】
- Overview of variable resistors - structure, operation and different applications
- Appium自动化测试基础 — Appium测试环境搭建总结
- wordpress切换页面,域名变回了IP地址
猜你喜欢
随机推荐
LeetCode 0108.将有序数组转换为二叉搜索树 - 数组中值为根,中值左右分别为左右子树
One question per day 1447 Simplest fraction
Alu logic operation unit
多屏电脑截屏会把多屏连着截下来,而不是只截当前屏
Daily question 1688 Number of matches in the competition
Overview of variable resistors - structure, operation and different applications
Wazuh開源主機安全解决方案的簡介與使用體驗
做 SQL 性能优化真是让人干瞪眼
[jailhouse article] jailhouse hypervisor
【Rust 笔记】15-字符串与文本(下)
Data visualization chart summary (I)
On the characteristics of technology entrepreneurs from Dijkstra's Turing Award speech
“磐云杯”中职网络安全技能大赛A模块新题
【Rust 笔记】17-并发(上)
【实战技能】如何做好技术培训?
Full Permutation Code (recursive writing)
R language [import and export of dataset]
Sword finger offer 06 Print linked list from beginning to end
全国中职网络安全B模块之国赛题远程代码执行渗透测试 //PHPstudy的后门漏洞分析
【Rust 笔记】14-集合(上)