我想在 <Scene
key="dashBoard"
component={DashBoard}
type="reset"
renderTitle={() =>
<View style={Styles.renderTitleStyle}>
<Image source={Images.logo}/>
</View> }
onRightButton={() => console.log('print')}
renderRightButton={() =>
<TouchableOpacity onPress={() => this.logOut()}>
<Icon name="md-power" color="#FFFFFF" style={{fontSize: 25, top: 0}}/>
</TouchableOpacity>
}
/>
方法内创建一个线程,并在结构被销毁后停止它:
logOut(){
console.log('logout');
}
这不能编译,我无法理解为什么:
new
如何解决此错误?
将来,我会为use std::thread;
struct Foo {
handle: thread::JoinHandle<()>,
}
impl Foo {
pub fn new(name: &str) -> Foo {
let name = name.to_string();
Foo {
handle: thread::spawn(move || {
println!("hi {}", name);
}),
}
}
pub fn stop(&mut self) {
self.handle.join();
}
}
fn main() {
let mut foo = Foo::new("test");
foo.stop();
}
实施error[E0507]: cannot move out of borrowed content
--> <anon>:15:9
|
15 | self.handle.join();
| ^^^^ cannot move out of borrowed content
,并会从Drop
致电Foo
。
答案 0 :(得分:8)
JoinHandle::join
的功能签名是:
fn join(self) -> Result<T>
这意味着该方法按值获取self
(接收者对象)(获取所有权/消费它)。但是你只能借用JoinHandle
;一个可变的,但仍然只是借用,不所有权。因此,您无法调用此方法,因为您无法将所有权从借用中转移到此join()
方法中。
解决这个问题的一种简单方法是,通过self
方法中的值接受stop()
:
pub fn stop(self) {
self.handle.join();
}
但是您会注意到在实施Drop
时无法做到这一点,因为drop()
具有签名fn drop(&mut self)
!坏消息!但是你可以使用一个小技巧,如下所述。请注意,加入drop()
中的主题可能不是一个好主意!阅读Matthieu M.'s answer了解更多相关信息!
如果你仍然认为,无论出于何种原因,你真的想加入drop()
中的一个帖子,你可以将JoinHandle
存储在Option<T>
中以保存它是否已经存在加入。如果您有Some(T)
,则可以使用方法Option::take()
从中获取T
(按值!)。然后你可以写:
fn drop(&mut self) {
// `self.handle` has the type `Option<JoinHandle<()>>` here!
if let Some(handle) = self.handle.take() {
handle.join().expect("failed to join thread");
}
}
答案 1 :(得分:3)
<强>不强>
这看似违反直觉,但在析构函数中加入一个线程(或进程)通常是一个坏主意。
请注意,要求加入不会导致线程自行停止;它只是等待让线程停止,而线程可能没有。导致这种情况发生的原因有很多:
是的,这是一个僵局。 隐式死锁。
一个特别令人讨厌的情况是,如果你当前的线程发生恐慌(发生了无法预料的事情)。放松开始...并阻止!而这个线程应该清理的所有资源永远都处于不确定状态。
更好的设计是创建一个明确的join
方法,它消耗self
(按值)。它还允许您返回Result
,以防加入导致错误。
为了让您的用户忘记明确加入panic!
,Drop
如果他们忘记了。
那是:
impl Foo {
fn join(self) -> std::thread::Result<()> {
self.handle.join()
}
}
impl Drop for Foo {
fn drop(&mut self) {
panic!("You MUST call either join on `Foo` to clean it up.");
}
}
注意:我知道在析构函数中恐慌是有争议的,但是当一个进程处于未知状态并且希望最好时,中止进程会更加安全。
如果你真的,尽管我发出了警告,想要用脚射击自己,使用Option
及其take
方法。
答案 2 :(得分:2)
join
签名中的问题:
fn join(self) -> Result<T>
所以为了修复你的代码,你需要这样的东西:
pub fn stop(self) {
self.handle.join();
}
答案 3 :(得分:1)
如果您不介意不安全的代码,则可以执行以下操作(请查看Matthieus answer为什么此 可能不是一个好主意)。
struct Foo {
handle: ManuallyDrop<thread::JoinHandle<()>>,
}
impl Drop for Foo {
fn drop(&mut self) {
unsafe {
let _ = ManuallyDrop::take(&mut self.handle).join();
}
}
}