ZYR:rcore_step_by_step-流水帐式记录
DeathWish5 opened this issue · 5 comments
概述
2019/7/16
配置好了rust windows开发环境。完成猜数字程序。
由于实习原因进度较慢,不定期更新。
问题
-
玄学问题:Blocking waiting for file lock on package cache lock 无限等待。
解决:重启电脑后解决。但尚未断定原因,可能由于电脑开启太多应用导致进程未知错误。
-
问题:直接使用 rand::random::<>() 与使用 rand::thread_rng().gen::<>() 有什么区别吗?
-
其他问题:在某些linux内核中,不可以使用浮点操作。为何在用户态可以使用,内核反而不可以?这么设计是出于那些考虑?假定在不考虑效率的情况下,有什么简单的方法或者库(比如编译选项)可以用整形模拟浮点吗?
内核编译模块时自带gcc参数 -mno-sse -mno-sse2,这直接导致了内核模块不能使用SSE,SSE2指令,但是这好像并不是说不能使用所有的浮点操作。
-
Blocking waiting for file lock on package cache lock 无限等待。
一般是另一个 cargo 程序正在运行,可能是 IDE 在后台自动执行 cargo。
可尝试 kill 掉所有 cargo 进程再试。 -
直接使用 rand::random::<>() 与使用 rand::thread_rng().gen::<>() 有什么区别吗?
rand::random
的文档中表示:This is simply a shortcut for thread_rng().gen().
所以看上去是一样的。
-
在某些 linux 内核中,不可以使用浮点操作。为何在用户态可以使用,内核反而不可以?这么设计是出于那些考虑?
浮点运算需要 FPU 协处理器的支持,上古时代的 CPU 没有这个东西,所以那个时候的 OS 也不支持硬浮点。
另一方面,一般 OS 内核不会用到浮点计算。并且引入浮点寄存器后,上下文切换会有更多开销。因此内核中往往不会使用硬浮点,而是用整数模拟。假定在不考虑效率的情况下,有什么简单的方法或者库(比如编译选项)可以用整形模拟浮点吗?
可以通过编译选项设置。gcc 我不太清楚,Rust 是在 target 描述文件中加入以下内容来设置的:
"features": "-mmx,-sse,+soft-float"
概述
2019/7/17
学习了所有权、引用、切片。
问题
-
引用的生命周期
参考如下代码
fn main() { let mut s = String::from("hello"); let rs = &mut s; // 正常编译运行 rs.push_str(", world"); s.push_str("! I'm tom."); }
fn main() { let mut s = String::from("hello"); let rs = &mut s; // 报错:cannot borrow `s` as mutable more than once at a time // 以下两行注释掉任意一行或者交换顺序,正常运行 s.push_str("! I'm tom."); rs.push_str(", world"); }
这种现象该怎么理解呢?操作可变引用与直接操作原值有什么限制吗?
-
引用的本质(先写下来,好像可以通过学习8、15章解决)
很自然想到对比C++的引用。在C++中,引用本质上和指针类似,汇编层面上通过传递地址实现(好像是,没考证)。直觉上,rust的引用应该也是这样实现的,但是:
fn main() { let mut s = String::from("hello"); let rs = &mut s; rs.push_str(", world"); (*rs).push_str("! I'm tom."); println!("{ }", s); let mut a : i32 = 3; let ra = &mut a; // ra += 2; 不能这样写 *ra += 2; println!("{ }", a); }
一方面,引用可以直接解引用之后操作原值,另一方面,对于
String
类型,引用不需要->
运算符就可以直接和原值一样操作,但是对于i32
就不可以,这仅仅是因为i32
是一个标量吗?
-
引用的生命周期
fn main() { let mut s = String::from("hello"); let rs = &mut s; rs.push_str(", world"); // 根据 Rust 最新的 NLL(Non Lexical Lifetime) 规则 // `rs` 在此处之后不再使用,生命周期在此终结,进而对 `s` 的可变借用在此释放 // 于是下面可以继续可变借用 `s` s.push_str("! I'm tom."); }
fn main() { let mut s = String::from("hello"); let rs = &mut s; s.push_str("! I'm tom."); // 此处 `s` 已经被 `rs` 可变借用,不能再次借用,故报错 rs.push_str(", world"); // `rs` 在此被使用,因此其生命周期持续到这里 }
-
引用的本质
这里的区别是 调用方法 和 运算符。
如果改成+=
运算符,一样会报错:rs.push_str(", world"); // ok rs += ", world"; // x *rs += ", world"; // ok
调用方法时编译器会自动解引用,直到找到一个存在的方法。
但使用运算符时就需要手动解引用。
注:关于自动解引用可参考这里,不过好像跟这个例子关系不大……
概述
2019/7/18-19
结构体、枚举,模块,常见集合,错误处理。
实践较少,没发现有价值的问题,明天好好看看例子,应该有启发。
问题
-
内核异常与用户态异常的区别
应用程序panic,会产生中断,切换到内核态执行异常处理例程,panic的话一般直接杀死进程然后调度。感觉上,内核的非致命进程发生错误,应该可以用同样的流程处理,甚至不用发生切换。但是今天在虚拟机上挂载了一个自定义的内核模块(TCP包过滤程序,不核心),发生了除0错(迁移到用户态后发现),系统的表现有两种:1.直接死机 2.出错进程停止工作失去响应(由于查不到进程号,不能人工kill),过一会后计算机开始轰鸣。那么内核的进程出错后的处理与用户态有何本质区别呢?为何我的虚拟机没有直接杀死错误进程?
概述
2019/7/18-19
结构体、枚举,模块,常见集合,错误处理。
实践较少,没发现有价值的问题,明天好好看看例子,应该有启发。
问题
- 内核异常与用户态异常的区别
应用程序panic,会产生中断,切换到内核态执行异常处理例程,panic的话一般直接杀死进程然后调度。感觉上,内核的非致命进程发生错误,应该可以用同样的流程处理,甚至不用发生切换。但是今天在虚拟机上挂载了一个自定义的内核模块(TCP包过滤程序,不核心),发生了除0错(迁移到用户态后发现),系统的表现有两种:1.直接死机 2.出错进程停止工作失去响应(由于查不到进程号,不能人工kill),过一会后计算机开始轰鸣。那么内核的进程出错后的处理与用户态有何本质区别呢?为何我的虚拟机没有直接杀死错误进程?
U worked so hard, so as to become a master of rust ! Respect professor Zhang !