最近都凌晨睡前写铁人赛,就怕隔天忘记Q
嘛 这次铁人赛真的学到蛮多的,算是复习吧。
原本可能搞不懂的还是得搞懂。
总之,快要进入到专案篇的部份了,就开始今天的内容ㄅ。
今天要讲的就是昨天已经预告过的多线程。
那多线程是许多人在修作业系统的恶梦,我在看清大教学的时候也觉得蛮难理解的,可能铁人赛後会再去重看一次全部教程吧。
那如基本上多线程程序会遇到的问题有
除了上面需要注意的点还有多执行绪的程序不一定每次的执行顺序会一样
这边举一个错误例子:
static mut a: i32 = 0;
fn main() {
unsafe {
a += 1;
};
}
这个在单执行绪的情况下运行是正常的
不过如果到多线程就会需要依靠运气来让他跑出想要的正确答案。
为什麽呢:
因为他被分成三步
那如果说这三步都在不同执行绪下执行就有可能发生 Race Condition 的问题。
可能就会像下面所说的执行
执行绪1. 执行第一步 暂存器 = 0
执行绪1. 执行第二步 暂存器 = 1
执行绪2. 执行第一步 暂存器 = 0
执行绪1. 执行第三步 暂存器 = 0
最後 a = 0
那这种问题一旦出现都很严重,假如说今天你领钱,执行绪2. 将领出的钱视为没领出
这样银行早就破产了,但是我好希望有一天领钱帐户余额不会减少
那处理方法很简单就直接使用 atomic 区块包着就好了
atomic 区块是代表说无法执行 context switch 的区块
那麽就能够成功避免说上述得情况
再举个例子
use std::thread;
fn main() {
for mut a in 0..=10 {
thread::spawn(move || {
print!("{} ", a);
});
}
}
那如果说执行这段程序这段程序是使用多线程来运行 for 回圈
那麽执行後会发现每一次的执行的输出值都会不同这是因为执行绪是乱数执行的。
那也就是他对於同一区块同时进行读写而导致的,所以需要确保他执行的顺序owo
OK 知道多执行绪会带来的问题後就可以开始想该如何解决了以及该如何撰写了!
那麽 Rust 有STD库中有两个模组正是来控制执行绪的分别是:
从 std::thread 开始讲吧
就以前面的程序码当例子 他会反覆运算产生 11 个 thread
而生成方法是使用 spawn 这个函数,并且 由於要使用 a 这个变数,所以需要使用 move 关键字来让 a 的所有权传输进新的 thread 里
那麽前面遇到的问题要怎麽解决呢
可以使用 join 来解决
join 就是让主 thread 去等待子 thread 停止运算
use std::thread;
fn main() {
for mut a in 0..=10 {
let th = thread::spawn(move || {
print!("{} ", a);
});
th.join();
}
}
就像这样
那麽如果说想要自定执行绪的话要怎麽做呢
使用 builder 函数去创建而不是 spawn
那麽使用 builder 的好处在於可以自由定义名称或是修改 stack 大小
这边暂且不赘述
今天的内容大概这样 主要是後面的内容我没有什麽把握能够讲好讲精确,希望各位读者见谅。
多执行绪要注意的东西真的很多,能避免错误的工具也很多 像是 Mutex 之类的等等
详细的话可以去 Rust Book 上寻找查阅。
总之,今天到这边,晚安
<<: 找LeetCode上简单的题目来撑过30天啦(DAY2)
>>: Day 5【JavaScript】可以看到,将近是20公分的深度
正文 过去我们在使用Kubernetes的权限,往往可能就是用admin.conf,或是servic...
当你进入我的眼帘,我们的命运就有了交集~ 看到 Observer,应该就知道今天要介绍的又是「观察...
DAY1 揭开序幕与 MongoDB 简介 前言 终於鼓起勇气要报名 iThome 铁人赛! 本系列...
Plotting regression line 继昨天画出XY关系图後,我们就会进一去想知道XY...
前言 今日的程序码 => GITHUB 我很喜欢这篇 CodeLab,我自己认为,如果这篇的内...