< 返回版块

kaifoon 发表于 2021-07-18 22:50

Tags:thread

评论区

写评论
作者 kaifoon 2021-08-02 09:46

朋友,你的代码编译没通过

--
👇
aariety: 可以使用 crossbeamscope

如果不想引入其他 crate,也可以使用 transmute 手动操作:

fn too<T: Send>(x: T) {
    let x: &'static T = unsafe { std::mem::transmute(&x) };
    thread::spawn(move || {
        println!("{:p}", x);
    }).unwrap().join().unwrap();
}

还可以使用尚未稳定的特性,目前在 nightly 可以使用:

fn too<T: Send>(x: T) {
    let x = &x;
    let builder = std::thread::Builder::new();
    unsafe {
        builder.spawn_unchecked(move || {
            println!("{:p}", x);
        }).unwrap().join().unwrap();
    }
}

注意:join 必不可少。必须保证所传递的引用的生命周期比线程的运行时间长。

作者 kaifoon 2021-08-02 09:35

具体的类型没有'static trait bound

--
👇
johnmave126: 我觉得最好还是先说明你实际要用的类型T,究竟是什么原因不能加'static的生命周期bound

aariety 2021-07-27 21:54

可以使用 crossbeamscope

如果不想引入其他 crate,也可以使用 transmute 手动操作:

fn too<T: Send>(x: T) {
    let x: &'static T = unsafe { std::mem::transmute(&x) };
    thread::spawn(move || {
        println!("{:p}", x);
    }).unwrap().join().unwrap();
}

还可以使用尚未稳定的特性,目前在 nightly 可以使用:

fn too<T: Send>(x: T) {
    let x = &x;
    let builder = std::thread::Builder::new();
    unsafe {
        builder.spawn_unchecked(move || {
            println!("{:p}", x);
        }).unwrap().join().unwrap();
    }
}

注意:join 必不可少。必须保证所传递的引用的生命周期比线程的运行时间长。

johnmave126 2021-07-20 00:05

我觉得最好还是先说明你实际要用的类型T,究竟是什么原因不能加'static的生命周期bound

作者 kaifoon 2021-07-19 19:33

怎么弄,transumte试过不行

--
👇
fakeshadow: Box::leak or std::mem::transumte

fakeshadow 2021-07-19 09:35

Box::leak or std::mem::transumte

7sDream 2021-07-19 03:50

https://docs.rs/crossbeam-utils/0.8.5/crossbeam_utils/thread/fn.scope.html

crossbeam::scope 了解一下,限制了 spawn 的线程必须在当前栈内结束,所以内部用 unsafe 去掉了 'static 的生命周期限制,让线程可以用对当前栈内变量的引用。

johnmave126 2021-07-19 02:02

spawn由于线程可能detach,导致线程的生命周期比程序长。如果有不是’static生命的引用,就有可能出现use after free。

可以参考一下:https://users.rust-lang.org/t/why-does-thread-spawn-need-static-lifetime-for-generic-bounds/4541/6

--
👇
kaifoon: 需求: 已知spawn传入的类型不会发生悬垂指针,指针被其他线程修改。就是不会发生内存问题的。在泛型trait bound不加 'static情况下,如何保证spawn 传入的类型是安全的就是编译通过,unsafe,safe都行,不接受FFI 代码如下:

use std::thread;

struct MyStruct;

unsafe impl Send for MyStruct {}

fn main() {
    let mystruct = MyStruct;
    too(mystruct);
}

fn too<T: Send>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}

报错如下:

error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:13:5
   |
12 | fn too<T: Send>(x: T) {
   |        -- help: consider adding an explicit lifetime bound...: `T: 'static +`
13 |     thread::spawn(move || {
   |     ^^^^^^^^^^^^^ ...so that the type `[closure@src/main.rs:13:19: 15:6]` will meet its required lifetime bounds

error: aborting due to previous error

For more information about this error, try `rustc --explain E0310`.
error: could not compile `hello`

To learn more, run the command again with --verbose.

如果是下面这种,应该不符合了

fn too<T: Send + 'static>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}
johnmave126 2021-07-19 02:02

spawn由于线程可能detach,导致线程的生命周期比程序长。如果有不是’static生命的引用,就有可能出现use after free。

可以参考一下:https://users.rust-lang.org/t/why-does-thread-spawn-need-static-lifetime-for-generic-bounds/4541/6

--
👇
kaifoon: 需求: 已知spawn传入的类型不会发生悬垂指针,指针被其他线程修改。就是不会发生内存问题的。在泛型trait bound不加 'static情况下,如何保证spawn 传入的类型是安全的就是编译通过,unsafe,safe都行,不接受FFI 代码如下:

use std::thread;

struct MyStruct;

unsafe impl Send for MyStruct {}

fn main() {
    let mystruct = MyStruct;
    too(mystruct);
}

fn too<T: Send>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}

报错如下:

error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:13:5
   |
12 | fn too<T: Send>(x: T) {
   |        -- help: consider adding an explicit lifetime bound...: `T: 'static +`
13 |     thread::spawn(move || {
   |     ^^^^^^^^^^^^^ ...so that the type `[closure@src/main.rs:13:19: 15:6]` will meet its required lifetime bounds

error: aborting due to previous error

For more information about this error, try `rustc --explain E0310`.
error: could not compile `hello`

To learn more, run the command again with --verbose.

如果是下面这种,应该不符合了

fn too<T: Send + 'static>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}
作者 kaifoon 2021-07-18 22:57

需求: 已知spawn传入的类型不会发生悬垂指针,指针被其他线程修改。就是不会发生内存问题的。在泛型trait bound不加 'static情况下,如何保证spawn 传入的类型是安全的就是编译通过,unsafe,safe都行,不接受FFI 代码如下:

use std::thread;

struct MyStruct;

unsafe impl Send for MyStruct {}

fn main() {
    let mystruct = MyStruct;
    too(mystruct);
}

fn too<T: Send>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}

报错如下:

error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:13:5
   |
12 | fn too<T: Send>(x: T) {
   |        -- help: consider adding an explicit lifetime bound...: `T: 'static +`
13 |     thread::spawn(move || {
   |     ^^^^^^^^^^^^^ ...so that the type `[closure@src/main.rs:13:19: 15:6]` will meet its required lifetime bounds

error: aborting due to previous error

For more information about this error, try `rustc --explain E0310`.
error: could not compile `hello`

To learn more, run the command again with --verbose.

如果是下面这种,应该不符合了

fn too<T: Send + 'static>(x: T) {
    thread::spawn(move || {
        println!("{:p}", &x);
    });
}
1 共 10 条评论, 1 页