多线程的介绍

  1. 进程是资源分配的最小单位,线程是cpu调度的最小单位
  2. 使用多线程的过程之中,遇到以下问题:
    (1). 竞争状态:两个多线程不一致的顺序访问数据或者资源
    (2). 死锁:两个线程相互等待对方停止使用其所用有的资源,造成两者都永久等待:
    如:A: 1->2->3 B:2->1->3 t1:A:1,B:2 接着等待t2: A:2 B:1
    (3). 只会发生在特定情况下且难以重现和修复的bug
  3. 编程语言提供的线程叫做绿色线程,如go,在底层实现了M:N的模型,M个绿色线程
    对应着N个OS线程。但是,Rust标准库只提供1:1的线程模型的实现,一个线程对应着一个
    Os线程
  4. 运行时代表二进制文件中包含的由语言本身提供的代码,这些代码根据语言的不同可以
    分为不同的大小,但是非汇编语言一定有一部分的运行时代码,但是一般来说,如果说一个
    语言"没有运行时",一般是说这个语言的"运行时"很小。Rust和C几乎没有运行时
  • 主线程未等待子线程结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//代码运行时先打印main中的,再打印thread中,并且到4就结束了,因为main函数先结束了
use std::thread;
use std::time::Duration;

fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("number {} in spawn thread",i);
thread::sleep(Duration::from_millis(1));
}
});//主线程先结束,没有等待子线程

for i in 1..5 {
println!("number {} in main thread",i);
thread::sleep(Duration:;from_millis(1));
}
}
  • 主线程等待子线程结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//代码运行时先打印main中的,再打印thread中,并且到4就结束了,因为main函数先结束了
use std::thread;
use std::time::Duration;

fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("number {} in spawn thread",i);
thread::sleep(Duration::from_millis(1));
}
});

for i in 1..5 {
println!("number {} in main thread",i);
thread::sleep(Duration:;from_millis(1));
}
handle.join().unwrap();//等待线程的结束
}
  • 第三种:先打印子线程,再打印主线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::thread;
use std::time::Duration;

fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("number {} in spawn thread",i);
thread::sleep(Duration::from_millis(1));
}
});
handle.join().unwrap();//等待线程的结束
for i in 1..5 {
println!("number {} in main thread",i);
thread::sleep(Duration:;from_millis(1));
}
}

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
use std::thread;

fn main() {
let v = vec![1,2,3];

let handle = thread::spawn(|| { //报错
//不知道v的生命周期
//所以编译器会报错
//因为如果drop(v),之后就不能够使用handle
println!("v = {:?}",v);
});
handle.join().unwrap();
}

使用move关键字避免错误

move关键字是将v转移至线程的闭包之中,之后就不能再主线程中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use std::thread;

fn main() {
let v = vec![1,2,3];

let handle = thread::spawn(move || { //报错
//不知道v的生命周期
//所以编译器会报错
//因为如果drop(v),之后就不能够使用handle
println!("v = {:?}",v);
});

handle.join().unwrap();
}