无法在产生的线程中调用函数,因为它“不满足要求的生存期". [英] Cannot call a function in a spawned thread because it "does not fulfill the required lifetime"

查看:123
本文介绍了无法在产生的线程中调用函数,因为它“不满足要求的生存期".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以运行这段代码

fn testf(host: &str) {}

fn start(host: &str) {
    testf(host);
    testf(host);
}

但是由于某些原因,我无法运行该程序:

but for some reason, I can't run this one:

fn testf(host: &str) {}

fn start(host: &str) {
    thread::spawn(move || testf(host));
    thread::spawn(move || testf(host));
}

由于以下错误

src/server.rs:30:5: 30:18 error: the type `[closure@src/server.rs:30:19: 30:38 host:&str]` does not fulfill the required lifetime
src/server.rs:30     thread::spawn(move || testf(host));
                     ^~~~~~~~~~~~~
note: type must outlive the static lifetime
error: aborting due to previous error

有人可以解释一下我,这是什么问题以及如何解决?

Can somebody explain me, what is wrong with it and how to fix it?

推荐答案

您的闭包捕获了一个字符串片,因此其环境的生存期不超过该片的生存期,而是

Your closure captures a string slice, therefore its environment has lifetime no longer than that of this slice, but thread::spawn() requires its argument to have static lifetime:

pub fn spawn<F, T>(f: F) -> JoinHandle<T> 
    where F: FnOnce() -> T, 
          F: Send + 'static, 
          T: Send + 'static

(请注意F: 'static要求)

这是必要的,因为当thread::spawn()产生的线程开始运行时,用于获取切片的字符串可能已被破坏. Rust实际上已经防止了您的代码中的错误!

This is necessary because when the thread spawned by thread::spawn() gets to run, the string from which the slice is taken may already be destroyed. Rust has actually prevented an error in your code!

有几种修复方法.

1)最简单的方法是为每个线程克隆字符串:

1) The simplest way would be to clone the string for each thread:

fn start(host: &str) {
    {
        let host = host.to_owned();
        thread::spawn(move || testf(&host));
    }
    {
        let host = host.to_owned();
        thread::spawn(move || testf(&host));
    }
}

这样,每个线程都会收到自己的字符串副本,该副本将在线程本身完成时销毁.

This way each thread receives its own copy of the string which will be destroyed when the thread itself finishes.

2)如果您知道线程应该在start()函数结束之前完成,则可以使用第三方库,例如

2) If you know that your threads should finish before start() function ends, you can use a third-party librariy like crossbeam to pass references into spawned threads:

extern crate crossbeam;

fn start(host: &str) {
    crossbeam::scope(|scope| {
        scope.spawn(move || testf(host));
        scope.spawn(move || testf(host));
    });
}

这样,start()将等待直到在scoped()中产生的两个线程都结束后再返回,确保host指向的任何字符串都不会被过早破坏.

This way start() will wait until both threads spawns in scoped() has finished before returning, making sure that whatever string host points to won't be destroyed prematurely.

以前,此类功能已包含在标准库中,但是找到了实现的方式不健全,因此已弃用;尚未将此功能的适当替代物重新添加回标准库中.

Previously such functionality was included in the standard library, but the way it was implemented was found to be unsound, so it was deprecated; a proper replacement for this functionality is yet to be added back into the standard library.

3)甚至另一种选择是使用Arc<String>在线程之间共享字符串,但这将需要在start()之外进行更重要的更改:

3) Even another alternative would be to use Arc<String> to share the string between threads, but this would require more significant changes outside of start():

use std::sync::Arc;

fn start(host: Arc<String>) {
    {
        let host = host.clone();
        thread::spawn(move || testf(&host));
    }
    {
        let host = host.clone();
        thread::spawn(move || testf(&host));
    }
}

使用这种方法,您需要将字符串保留在Arc(这是原子引用计数"指针)内,因此这需要您更改调用start()的代码.克隆可能更好.当然,如果您不想共享&str而是共享&SomeStruct,而其中SomeStruct大且/或不可克隆,则无法避免对xor Arc进行作用域限定.

With this approach you need to keep your string inside an Arc (which is an "atomically reference counted" pointer), so this requires you to change the code which calls start(). Cloning is probably better. Of course, if you want to share not &str but &SomeStruct where SomeStruct is large and/or not cloneable, there is no way to avoid scoping xor Arc.

这篇关于无法在产生的线程中调用函数,因为它“不满足要求的生存期".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆