本文以和为例,讨论Rust中的和是如何保证线程安全的。
基本概念
和位于标准库模块中。它们属于标记trait,也就是说,它们没有方法,也没有内置任何功能。它们的作用是:
如果类型实现了,则将类型的值传递给另一个线程不会导致数据争用(data rases)或其他不安全性
如果类型实现了,则将类型的引用传递到另一个线程中不会导致数据争用或其他不安全性(暗含着)
也就是说,与类型跨多个线程共享时有关,而则讨论类型被move到另一个线程的行为方式。
Allowing Transference of Ownership Between Threads with Send允许在线程间转移所有权
Allowing Access from Multiple Threads with Sync允许多线程访问
在Rust的标准库模块中,为所有类型默认实现了和。
线程
Rust与线程相关的内容位于标准库模块中。Rust中的线程,是对操作系统线程的直接封装。也就是说是本地线程,每个线程都有自己的栈和本地状态。
函数的函数签名如下:
通过函数签名我们可以看出,spawn()接受一个可调用的(通常是一个闭包),其被调用一次,并包含和的数据。也就是说只有实现了的类型才可以在线程间传递。
同时限定阻止线程之间共享借用的数据。闭包可以捕获外部变量,但默认情况下它是通过引用捕获的。示例代码中如果没有关键字,则闭包将不会是的,因为它包含借用的数据。
和示例
线程间传递可变字符串。
表示“Reference Counted”(引用计数),单线程引用计数指针。
编译会报错,错误信息告诉我们,无法在线程之间安全地发送。
这是因为没有实现。我们可以使用来共享所有权。
编译还是报错,错误信息告诉我们,把不可变借用当作可变借用了。
这是因为默认是不可变的。我们可以使用之前文章中提到的具有内部可变性的类型。
表示可变的内存位置,运行时检查借用规则。
编译再次报错,错误信息告诉我们,无法在线程之间安全地共享。
这是因为没有实现。
结语
Rust通过和这两个标记trait,将类型贴上“标签”,由编译器识别类型是否可以在多个线程之间移动或共享,在编译期间发现问题,消除数据竞争,从而保证线程安全。
领取专属 10元无门槛券
私享最新 技术干货