< 返回版块

0xe994a4 发表于 2023-03-03 17:40

use std::sync::atomic::AtomicBool;

static FOO: AtomicBool = AtomicBool::new(false);

#[tokio::main]
async fn main() {
    println!("foo: {:?}", FOO);

    let bar = tokio::spawn(async move {
        println!("foo: {:?}", FOO);
    });

    bar.await.unwrap();
}

在多线程编程下,如果不是全局变量,要用 Arc 来实现线程间传递,但在声明为 static 时不用Arc。

  • 为什么在声明为 static 时不用 Arc ?是因为全局生命周期吗?
  • 不理解 move 到 async 闭包的时候具体是什么发生了 move,是 FOO 的引用吗?还是 FOO 本身?

评论区

写评论
作者 0xe994a4 2023-03-06 10:36

另外,官方文档也提到

Static items do not call drop at the end of the program.
作者 0xe994a4 2023-03-06 10:32

谢谢几位大佬的回答,:-)

小结如下

为什么在声明为 static 时不用 Arc ?是因为全局生命周期吗?

Arc 是为了在多线程环境下跟踪共享变量的引用情况,确保变量被 drop 的时候没有被引用的情况。 static Atomic 是在多线程环境下,但因为其生命周期是全局的,比任何线程的生命周期都要长,所以不需要考虑通过 Arc 来跟踪。

不理解 move 到 async 闭包的时候具体是什么发生了 move,是 FOO 的引用吗?还是 FOO 本身?

move 是指变量的所有权发生移动,是作用域发生了变化。因为 statis Atomic 的作用域是全局的,所以根本不会发生move。 至于具体的实现,皮卡丘大佬提到是编译后被替换成固定的内存地址,这个还不懂,要继续研究研究。

hax10 2023-03-03 18:54

在多线程编程下,如果不是全局变量,要用 Arc 来实现线程间传递

Arc是多个线程共享数据的一种办法,并非是唯一一个,比如还有Mutex等方式。

关键是共享的变量必须满足Sync的要求。Arc、Mutex、AtomicBool等类型无论全局还是局部变量都属Sync,所以同样都能共享。AtomicBool因为本身属Sync就不用再次包装了。

但在声明为 static 时不用Arc。

非static的Sync类同样不用Arc。

不理解 move 到 async 闭包的时候具体是什么发生了 move,是 FOO 的引用吗?还是 FOO 本身?

一般move会把变量的所有权移植到闭包里,闭包运行完了就drop删掉这些变量了,但是因为FOO是static它就一直存在且能保证不变,于是编译器没必要扯到所有权了,这一点前面的人也说了。

Pikachu 2023-03-03 18:40

第一个问题,你看一下Arc的全名就行了Atomic reference counter。全局变量不需要reference counter,因为它完全不会被drop。

第二个问题,应该根本没有发生move。static是有静态生命周期而且全局可见的,在编译之后会被替换成固定的内存地址,所以根本不需要从main的scope里面获取FOO的reference。

github.com/shanliu/lsys 2023-03-03 18:08

Atomic 都是原子操作 有所有权又不是引用 为什么要Arc在打包一次?

1 共 5 条评论, 1 页