时间:2025-01-12 12:22
人气:
作者:admin
线程之间共享内存数据,即go中部分人所憎恶的方式!
然而,这个方式并非没有其优点,否则操作系统也不提供这种实现方式。
闲言少序,上正文!
#[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")] pub struct Mutex<T: ?Sized> { inner: sys::Mutex, poison: poison::Flag, data: UnsafeCell<T>, }这个sys::Mutex是一个原子:
pub struct Mutex { futex: Atomic, }用于持有锁position(位置标记/占有标记)是一个原子布尔,用于表示是否被占有data就是原始的数据了。
#[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> { unsafe { self.inner.lock(); MutexGuard::new(self) } }这段代码的大概意思:调用操作系统的内部锁,返回一个新的MutexGuard。完整的结果就是包含一个锁和一个结果
use std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..10 { let c = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = c.lock().unwrap(); *num += 1; println!("线程{:?}正在执行,得到{}", thread::current().id(),*num); }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); }
借用Arc指针(多线程使用的,可以共享数据)和Mutex锁实现简单的数字自增游戏! 很像餐桌上大伙共享一个公勺,有了公勺你要干什么都可以,但一个时刻只有一把公勺!

根据书本的要求,我特意构建一个死锁的代码。
发生死锁的最主要原因是互相等待对方持有的资源,好比劫匪持有人质,警察要人质,常常会陷入死循环!直到一方崩溃
use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; fn main() { let 人质 = Arc::new(Mutex::new(5)); let 自由 = Arc::new(Mutex::new(10)); let h0=Arc::clone(&人质); let w0=Arc::clone(&自由); let 劫匪=thread::spawn(move || { //线程0先获得人质资源,然后等待一段时间再获得自由资源。 let mut _人质 = h0.lock().unwrap(); thread::sleep(Duration::from_millis(10)); println!("我已经持有人质,快点让路!"); let mut _自由 = w0.lock().unwrap(); let 矛盾文学奖 = (*_人质) * (*_自由); println!("线程{:?}正在执行,得到{}", thread::current().id(), 矛盾文学奖); }); let h1=Arc::clone(&人质); let w1=Arc::clone(&自由); let 警察=thread::spawn(move || { //线程1先获得的自由资源,然后等待一段时间再获得人质资源。 let mut _自由 = w1.lock().unwrap(); thread::sleep(Duration::from_millis(10)); println!("赶紧放了人质,否则爆你狗头!"); let mut _人质 = h1.lock().unwrap(); let 矛盾文学奖 = (*_人质) * (*_自由); println!("线程{:?}正在执行,得到{}", thread::current().id(), 矛盾文学奖); }); 劫匪.join().unwrap(); 警察.join().unwrap(); println!("众人在围观...."); let _人质 = 人质.lock().unwrap(); let _自由 = 自由.lock().unwrap(); let 矛盾文学奖 = (*_人质) * (*_自由); println!("Result: {}", 矛盾文学奖); }

* 1.Send 标记 trait 表明实现了 Send 的类型值的所有权可以在线程间传送。几乎所有的 Rust 类型都是Send 的,
* 不过有一些例外,包括 Rc<T>
* 2.任何完全由 Send 的类型组成的类型也会自动被标记为 Send。
* 几乎所有基本类型都是 Send 的,除了第二十章将会讨论的裸指针(raw pointer)
* 3.Sync 标记 trait 表明一个实现了 Sync 的类型可以安全的在多个线程中拥有其值的引用
* 4.类似于 Send 的情况,基本类型是 Sync 的,完全由 Sync 的类型组成的类型也是 Sync 的
* 5.通常并不需要手动实现 Send 和 Sync trait,因为由 Send 和 Sync 的类型组成的类型,
* 自动就是 Send 和 Sync 的。因为它们是标记 trait,甚至都不需要实现任何方法。它们只是用来加强并发相关的不可变性的
* 6.手动实现这些标记 trait 涉及到编写不安全的 Rust 代码
看看Arc的部分源码:
#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Arc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { ptr: NonNull<ArcInner<T>>, phantom: PhantomData<ArcInner<T>>, alloc: A, } #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Send> Send for Arc<T, A> {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Sync + Send, A: Allocator + Sync> Sync for Arc<T, A> {}
这里的实现,并没有代码,包括Send和Sync,如作者言!
因此,顺便提一下,rust的trait不是java之类的接口,它具有更多的功能
同时,这也意味着,许多功能是编译器实现的。
避免死锁的方法,有多种,这里只能列出其中一二比较简单有效的实践。
本文来自博客园,作者:正在战斗中,转载请注明原文链接:https://www.cnblogs.com/lzfhope/p/18664452