赞
踩
作者:Mara Bos
出版社: O’REILLY
ISBN:978-1-098-11944-7
std::thread::spawn
来产生新的线程,该方法需要一个参数,参数是该线程用于执行的函数(function),可以通过thread::current()::id()
来获取当前线程的ID,该ID仅能用于比较和复制,并且无法保证生成的ID是连续的;let t = thread::spawn(f)
的返回值(是一个JoinHandle类型)通过t.join().unwrap()
来回收;println!
宏使用了std::io::Stdout::lock()
锁来确保每一次打印不被其他线程的打印干扰;spawn
函数有一个'static
静态生命周期限制,要求spawn的函数必须在整个程序(program)运行时存活,正常通过fn function()
声明的函数没有问题,但是闭包(closure)通过引用捕获(capturing by reference)局部变量的时候,这个闭包可能不会永久存活,因为当局部变量销毁时,闭包捕获的引用也将失效。详见原书page4;std::thread::spawn
实际上是std::thread::Builder::new().spawn().unwrap()
的缩写,可以通过std::thread::Builder
来定制化产生的线程,例如分配堆栈空间、给thread取一个名字(std::thread::current().name()
);std::thread::scope
来声明一个有限范围的线程,只要确定scope的周期小于局部变量的生命周期,就可以安全地在scope范围内spawn函数来借用局部变量;详见page5;static
关键字来声明静态变量,该变量的生命周期是整个程序,其他的线程可以access该变量但不能own这个变量,因为它是被整个程序(entire program)拥有(own);Box::leak
来释放指针的所有权,保证永远不drop,从而使得该指针拥有静态生命周期,可以被所有的线程借用;'static
生命周期不一定表示该值在程序一开始就存在,但一定会存活到程序结束为止;std::rc::Rc
与Box
类似,但是带有引用计数(reference counted),它的clone
的结果是同一个指针,与Box的clone不一样;Rc并非线程安全,因此不能send
到别的线程中,可以使用Arc
,它是Rc
的线程安全版本;unsafe
,否则不可能写出通过rust编译器安全检查的非安全代码;std::cell::Cell<T>
仅仅包裹(wraps)一个T类型,在共享借用的情况下允许内部可变,但仅仅允许使用者把里面的值复制出来(copy out)或者取出(.take()
)以及完整替换(replace as a whole),而且仅能在单线程中使用,不支持多线程;std::cell::RefCell::<T>
与Cell的区别在于RefCell可以借用(.borrow()
)T的内容(content),有一点小小的运行时花费,同时RefCell能够追踪所有的借用,如果在T已经被可变借用(.borrow_mut()
)的情况下再去借用,程序会panic,反之亦然;与Cell一样,RefCell也只能在单线程中使用;Mutex
和RwLock
是RefCell的并发版本,意味着他们支持多线程使用,与RefCell不同的地方在于,RefCell检测到互斥的借用(如可变借用和不可变借用同时出现)会panic,而Mutex和RwLock会等待(或者说sleep),直到互斥条件接触时继续下一步,RwLock()允许可变和不可变借用,而Mutex仅支持独有借用;Atomic
类型是Cell
的并发版本,但是不像Cell是模板类,Atomic没有Atomic<T>
类型,而是针对内置类型一个个实现,例如AtomicBool
;UnsafeCell
是内部可变性的源语(primitive),像Cell
和Mutex
等等提供安全内部可变性的类型都是通过UnsafeCell实现的,UnsafeCell内部包裹一个裸指针(raw pointer);Send
表示它的所有权可以转移到别的线程中,一个类型可以Sync
表示它的共享引用(shared reference,&T)可以转移到别的线程中(也就是send);Send
和Sync
的,如果一个新的类型里的成员都实现了Send
和Sync
,那么这个类型也自动实现了这两个trait;如果想破解这两个自动实现的trait,可以使用std::marker::PhantomData<T>
往struct里添加一个没有实现Send和Sync的成员变量,例如Cell<T>
,详见page16;Send
和Sync
,如果需要实现这两个trait,需要使用unsafe关键字;Mutex<T>
通过lock()
方法来获取锁,得到一个MutexGuard
类型,保证已经获得了这个锁从而对其保护的内容进行独有修改,通过Drop()
方法来解锁,into_inner()
方法把Mutex的所有权夺走,使之不再被任何线程所引用,不再能进行locking操作;.lock()
来获取锁的时候获取一个PoisonError
,表示这个Mutex已经中毒(poisoned),可以把poisoned状态传递给所有试图获取这个锁的users;.lock()
返回的结果用let
绑定变量也许写起来很方便,但是会容易走进一些不容易察觉的陷阱,当用match, if let, while let
等语句来绑定等号右值的lock()
时,会把锁持有直到{code block}
全部执行完才释放,而不是if let
语句结束时,详见Page21;Mutex<T>和RwLock<T>
都要求T实现Send
,但是RwLock额外要求T实现Sync
;Mutex<()>
或者自己定义一个zero-sized类型来保护临界区;std::thread::park()
来暂停一个线程,当满足某些条件后通过unpark()
来唤醒线程,例子详见Page24;park()
之前收到了一个unpark()
消息,这个消息不会丢失,而是记录下来,下次收到了park()
消息的时候会迅速unpark()来运行后面的代码;但是unpark()
只会被记录一次,没有park()的线程收到了2次unpark()只会记录一次;park()机制比较适合1 consumer 1 producer场景;std::sync::Condvar
可以用于处理多个consumer需要被notify的情景,notify_one
用于唤醒一个等待的线程,notify_all
用于唤醒所有等待某个条件的线程;注意wait()
方法把Unlocking, waiting, relocking
操作集于同一个函数内,并且保证是原子操作,例子详见Page27,通常Condvar
只搭配单个Mutex
;Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。