Rust Atomic 笔记

basic of rust concurrency 内部可变性是指可以通一个不可变引用来实现对内部数据的修改。标准库中有Cell<T>,Cell相当于持有这个Obj,要做修改只能先把T move出来再把T塞回去。RefCell<T>不但持有这个obj,还会维护一个引用计数,如果在运行时有多个Mut借用时,会panic。 RwLock是多线程版本的RefCell,但是多个可变借用时,或者说多个写时,会block住试图拿这个可变借用的线程,让它进入sleep。而Mutex不像Rwlock可以实现多个可读借用,mutex是彻底的独占的,其它线程都必须等待锁的释放。 UnSafeCell是实现内部可变性的关键类型,它只有get函数可以得到一个底层类型的raw pointer,UnsafeCell没有任何保证安全性的限制,需要用户自己来进行安全性的保证。一般不会直接用unsafe cell,都是包装成另一个类型来限制使用,比如实现成cell或者mutex。 Sendtrait意味着这个类型的所有权可以在线程之间转移,Synctrait意味着这个类型可以在线程之间共享。 一个struct如果所有的类型都是send和sync,那它本身也是send和sync的,如果要实现非send和sync的话,可以用phontomdata 标记类型。PhantomData用于标记Struct非sync,毕竟这是个zero sized type。 给一些非auto trait实现send和sync是unsafe的,因为取决于其中类型的具体实现,所以安全性需要自己来保证。 rust的mutex,实现了一个其它线程如果持有了mutex,但是panic了,这个mutex就是poison的机制:rust mutex doc。 mutex一些值得注意的点: if let的scope。 if let Some(item) = list.lock().unwrap().pop() {//会lock到这个if结束 process_item(item); } if list.lock().unwrap().pop() == Some(1) {//在进入body前,MutxGuard就已经drop掉了。 do_something(); } rust 2024做出的一个if let的小修改,即if let的表达式生命周期不会延长到else body中去:rust 2024 doc 大多数的读写锁的实现都会block新的读者出现,当写者等待时,因为可能会多个读者共享导致写者一直要等待,这是读写锁中一个经典的饥饿问题。 ## parking and condition variables 当一个线程在等待别的线程的通知的时候,这种叫thread parking,parking的时候,线程会进入睡眠,唤醒可以用unpark。 在实现上,unpark有一个很重要的特性是,有一个信号保留机制,即unpark在park之前执行了,这个park也不会让线程进入睡眠,因为消费者需要对生产者的每一个unpark都有响应,否则会有丢数据的风险。 但是unpark并不能叠加,所以unpark两次后,再Park两次还是会线程进入睡眠。 条件变量一般是与mutex结合使用,传入同一个mutex,一个线程wait,一个线程notify。如果两个线程在操作同一个条件变量但是不同的mutex,会引起panic. Atomic and Memory order 原子类型可以在多线程间安全的访问和修改,但是依赖于Memory Ordering。比如最简单的order,Ralex,Relax只能保证单个变量的一致性,而多个变量间顺序无法保证。 atomic i32的溢出是回环的,不像普通的i32,溢出是会panic的。 为什么需要memory order?CPU会为了优化而把程序中的指令进行重排,写的是什么顺序,执行起来可能是别的顺序。 Happens before即保证A发生在B之前,但是在多线程中却是不一定的,使用锁可以保证,或者更严格的memory ordering。 ...

April 10, 2025 · 2 min · linxy

2024总结

好久没有写过年度总结类的文章了,最大的原因是在年底回忆起来,一年可能什么也没做,实在不太好写;即使写出来也会是充满了悔恨的文字,颇有熬夜之后,临睡之前的悔恨之意。 扯远了,那么2024年做了些啥呢? 运动 2024年最大的成功就是完成了两场半程马拉松,备赛时间从7月到10月底,刚好四个月。最好成绩是在杭州以1小时43分钟完赛。本来目标应该是跑进140的,但是在10月中的时候,一周无休的情况下,出去骑了100km,导致自己左脚踝受伤了,后面就只能停跑,到11月初参加比赛的时候,有氧水平掉了很多;杭州马拉松跑完的时候,脚真的是疼的不行,休息了一周硬顶上了南昌马拉松,以150完赛,当时感叹一下能完赛就算成功吧。 在当前时间节点看来,备赛的4个月是我感觉状态最好的时候,睡眠质量好,吃的也多,爬山也很轻松。多运动确实有好处吧。骑车今年骑的不多了,因为秋天转跑步了,所以后面都只是穿插了一下骑行活动,但是今年依旧跑了1000公里,骑了2000公里。 25年的目标就是以330完赛全马吧,虽然现在一个比赛都没中过,也没开始备赛。 书 今年读了43本书,大多是推理小说与读库,还有一些文学类的,举几本印象深刻的。 《流俗地》,年初读的,读了之后就感叹道肯定是个人24年TOP1的书,文笔无可挑剔。也算是为我打了南洋文学的一扇门吧。 《罪与罚》,年尾读的,读完后感觉陀爷真是神人,对杀人这件事的心理描写拿捏的如此精准,可见一定杀过人。 《悉达多》,主角宛如圣人一般的寓言故事。 《雾切7》,我们在群里多次提到了雾切,只能说这作的开篇和结尾确实花了心思,也是写的最好的。 游戏 今年唯一打完的单机游戏是baldr sky,好多游戏只打了个开篇就没有玩了。其中的原因是有些游戏后面是个悲剧,我不太愿意面对。有些是我人太浮躁,玩不太下去。开了很多游戏坑,还是得沉下心来好好体验这些游戏啊。 一句话总结就是上半年大多数时间在打雀魂,下半年跑步几乎不打游戏,12月在打CS。 剧与动漫与电影 今年看了不少剧,看的好电影也不少,提一些印象深刻的 《我的天才女友》123季都看完了,第4季看了一半,前面123季拍的真很好,让我感觉老意大利真的美。 《好东西》,算是年度好电影了吧,我看完的体验是到底谁在急眼呢,很多人都急眼了,感觉被攻击的是自己,可是电影中并没有攻击别人。电影更多的是表现女性生活,可以说并不止步女性的生活。 《因果报应》,应该是我的年度悬疑电影吧。即便是印度电影,仍然体现的是女性主义的核心。 《恶魔的破坏》,虽然还没有看完,但是值得我写一笔,动画体现的是日本的一种真实,而这些真实正在被消费,我感觉很诡异,但是实际上这种真实就是用来消费了,消费了才能有反馈啊。 《异形》,retro风格的电影,镜头挺有讲究的,算是看的爽的一类电影。 《JOJO5》,算是星尘十字军之后最好的一部吧,布姐的精神最好的诠释了黄金之风。 《葬送的芙莉莲》,应该算我的年度动漫,制作好,音乐好听,周指活。 《请回答1988》,18年开始看的,终于在今年看完了。几度看泪目了,时代与群像剧的TOP1吧。另外提一嘴《小巷人家》,本来能超越1988,可惜前8集能看。 技术 今年尝试给Rust Analyzer提了几个PR,给apache下面的项目做了贡献,虽然都是些小小的,但是至少跨出了自己做开源的第一步,打破了自己心目中神化了提开源PR这么一件事的印象。其实大多数项目都一样,只是草台程度不同的区别。 Rust方面读了Rust Atomic(这是本好书),然后拿Rust写了一个私活项目,可能也有几万行吧,算是实践的部分。另外这个项目还有客户端部分,写了一个月的avalonio,感觉写GUI体验真不太好,只能说GUI的editor跟游戏的editor都一样,真要做的好用,确实太难了。 另外读了几本技术书,但是感觉都一般,就不提了。 可见25年还是得多写多读,不能再懈怠了。 生活 今年9月买了一辆车,极大的扩大了行动的范围,虽然因为我们太宅,没有太出去走,但是至少多了一个出行的选择。 家里三只猫,两只在年初的时候治好了病毒性口炎,也就年中的时候小猫肠胃炎去了一次医院,相对来说,猫仔的生活也算是很好了。 去了一次胡彦斌的演唱会,爽听了三小时,也算是值回了票价了。 去了一次初音的演唱会,体验了一下打call,虽然中文歌有点多,但是体验仍是不错的,可能这就是二次元吧。 总结 24年当时定下的目标其实很简单,就是走出舒适区,多去体验体验生活,现在来看,基本完成了目标了;体验了很多之前没有干过的事,看过不少自己以前没有看过的电影,剧的类型。 那么展望25年,25年的目标就是技术上精进一步,搞一个side project试试,游戏上打完海猫与BG3,十三机兵,阅读上一定要读完的是陀爷的书;运动上330完赛全马。

December 30, 2024 · 1 min · linxy

终结这一切吧!Baldr Sky游玩感受

去年这时候,mwish 推荐给我一个galgame:Baldr Sky,我一直以来对galgame是不太感冒的,总感觉是与色色有关的游戏,而在游戏中寻找这种元素似乎是一件比较蠢的事;另外一个原因是,在我的认知中,一个黄油很难会有什么好的人物塑造,上来就推倒这种剧情显的很傻。而baldr sky是一个颠覆了我对galgame认知的作品,剧情音乐战斗都是超一流的优秀,而H的部分在这些看来真的很显的多余。 蕾线 作为开篇的线,本线做的非常好,玩家刚上手游戏,并不知道这个世界是怎么样的,而主人公甲在剧情中也是失忆状态的,所有的世界观与剧情都会随着记忆的恢复慢慢展开给玩家。不知道是不是故意而为之,制作组把蕾这样的一个人物放在最前面的,让后面的线推的时候,很难无视掉rain的付出,从而更加加深了对蕾的印象。蕾的人物塑造也非常鲜活,战场上给甲爷辅助,生活上给甲爷如同贤内助一般的照顾,可以说蕾是最完美的忠犬。在后面的线中,蕾无法作为女主出现在主流剧情中,但是仍然表现出来了对甲的忠诚,对甲隐藏的爱,这让我感觉非常的对不起她,难怪蕾是人气最高的角色。蕾线的Good ending是甲爷跟蕾远走高飞,过上了幸福的生活,可以说是非常甜的结局了,如果故事只限于此,而它将是平庸的作品。 菜叶线 菜叶线我印象最深的是结局中那个浪漫的场景,菜叶线紧接着蕾线,慢慢的把这个世界发生的事更加细化的展开来,让玩家发现这个世界不只是简单的一条故事线那么简单,总会有人死去。菜叶是一个非常可怜的女孩子,对老师充满了信任,最后却被利用了,不过我感觉这条线的情感有点牵强。在这条线中的千夏死掉了,从而引出了千夏线。 千夏线 我对千夏线只有愤怒,千夏塑造的非常好,学生时期的乐观与直球都是在隐藏自己,到后面发现了自己目标,哪怕让自己死也要达成目标。但是,这条线的甲爷塑造的太失败了,居然为了千夏大杀特杀,手刃蕾与魔狼的人,这对我来说简直不理喻,甲爷不是这样一个角色,为了爱情可以抛弃所有的人啊。千夏惨也是真的惨,千夏线她能得到幸福也是应该的。但是最后居然住到了Rain家里,这特么是什么鬼?还要在她家做。真是见鬼。 亚季线 我个人觉得亚季线真的是编剧写的最好的一条线,主要是在情感上被编剧牵着走,对于是不是乱伦这个问题,我感觉我的心情在过山车,而编剧用了好几层诡叙来震撼玩家。而亚季与情感线在我看来也比千夏与菜叶来的更加自然。 真线 真线其实我感觉更多的像是工具人线一般,因为情感上似乎也不是很能自恰,要说喜欢,我觉得真最多只是崇拜吧,而真因为一个恶作剧让自己承担上了无比沉重的责任,这样的写法让真这个角色更加有血有肉了。 空线 个人觉得空线其实写的挺一般,主要是文本量摆在那,但是要做的事情太多了,前面还要插进去一些救回各个女主,有些太过于冗长,如果更多的笔墨分到与空的情感交互上就更好了。不过空线作为收篇线,后半段非常的好,一个燃系机甲游戏,大甲收到各个世界线的甲的信念与记忆后,大喊Dr19,终结这一切吧后,BGM响起,与Dr19的战斗开始了,情感在这一刻到达了最顶峰,千千万万场战斗,最终都是为了救空,而空也独自撑了千万年。打完了Dr19后,我感觉到一丝解脱,终于结束了,终于救回了空。 jihad与沉默之空的音乐也为本作增色许多,在与千夏的战斗中,响起了BGM之时,真是太带感了。 战斗系统简约但不简单,也是到后期我才开发出一套连招可以输出很高,才在决战之时不那么痛苦,但是空线的战斗实在太多了,有些战斗真的又臭又长了。最后的True ending我也没有再打了,只能云一下了。 长达69小时的游玩,只能说这游戏确实是神作。 一些缺点:游戏不能放其它盘,容易闪退,而空线闪退频率太高了,好多战斗我都打了好多遍。 个人喜好线:空线=亚季线=rain线 > 菜叶线 > 真线 > 千夏线 个人女主喜好:蕾 = 空 > 千夏 > 亚季 > 真 > 菜叶。

July 8, 2024 · 1 min · linxy

systemd-boot添加Windows引导项

前言 最近把系统换成了CachyOS,用上了ZFS,这个发行版做的一些Tricky还是可以的,例如一些fish的脚本,还有软件与DE的自定义项都比较简洁,比ArcoLinux强上不少。 我的情况是有两块NVMe的硬盘,一块是Windows系统,一块则是CachyOS。我的期望是用Linux Boot Manager去引导两个操作系统,比用Windows Boot Manager去引导Linux要好操作不少。 ...

October 5, 2023 · 1 min · linxy

raft extented论文笔记

raft基础 一个raft集群一般来说有5个服务器结点,能让系统承受其中任意两台的down掉。每个服务器一共有三个状态,leader,follower,candidate,follower被动的接受来自candidate与leader的消息并作出回应。leader handle了所有了所有的客户端的请求,如果follower接收到了请求,会重定向到leader那去。 raft把时间分成任意长的阶段,从选举开始,每个阶段都是一个连续增长的整数,至少有一个或者多个candidate会尝试成为leader。如果有一个candidate成为了leader,则接下来的term,它将是leader。在一些情况下,选举会出现,平分票数的情况,这种情况,term将会维持没有leader的状态到结束,到下一次的新的选举。 不同的服务器 可能感知不到不同的term之间的转换,或者根本不知道有选举这回事,在这其中,term充当了一个逻辑时钟的作用,能让服务器能检测过时的信息,比如落后的leader。每一个服务器有一个current term number,随着时间增长,当服务器之间通信时,current term 会被 交换,如果有一个服务器的term小于别的,就会更新自己的,如果一个canditate或者leader发现它自己的term过时了,就会马上转变成follower,如果服务器收到了一个过时的请求,则会直接拒绝这个请求。 raft的服务器之间用rpc请行通信,其中RequestVote用于canditate 来进行选举,AppendEntries 用于分发log与当心跳包(事实上是无论收到一个请求,都应该重置time out chekcer)。另外 还有一个转移快照的rpc。之后 再说。 选举 raft使用心跳机制来触发选举。当服务器启动的时候,它们都是follower,follower在收到来自leader或者 candidate合法的rpc请求之前,一直是follower,leader会周期性的发送心跳包来保持leader的权威性,心跳包是一个空的AppendEntries,不带有Log entries。当一个follower一个election timeout后没有收到心跳包,则认为leader没了,将开始一轮选举,选出一个新的leader。 为了开始一次选举,follower会给current term+1然后转变成candidate,然后投自己一票,然后同时发起RequestVote RPC给别的服务器。一个candidate会持续到以下三件情况出现,(a)它成了leader,(b)其它服务器成了leader(c)一段时间过去后,没有server成为leader。这将在之后讨论(应该是过一段时间重新发起) 一个candidate如果收到了整个集群中大多数的投票 (with same term),就会成为leader。每一个服务器最多只能投出一票。这个大多数 的规则决定了,在一个term里,只能一个candidate成为leader。一旦candidate成为了leader,则会开始发送心跳包给其它所有的服务器,来保证自己的权威与阻止其它服务器发起选举。 在投票的过程中,可能 会收到来其它服务器发来的AppendEntries RPC来声称自己是leader,这种情况,看leader的term与自己的current term的大小,如果比自己大,那别人就是leader,自己将退回到follower的状态,如果比自己小,就是拒绝别人的RPC call,并继续进行选举。 一个选举如果选不出一个leader那就是分裂的选举,即没人得到大多数票,这种情况下,会等待超时直到下一次的选举,但是如果 没有做额外的操作,分裂的选举会不停的进行下去。 raft采用了随机的选举超时来保证split vote是很少见的并且能快速的被解决。即每一个服务器的election timeout不一样,在重新发起选举的之前会等待这个timeout,timeout少的会先发起选举。一般的timeout会选择一个区间比如150-300ms之间。这样会有一个服务器超时完成并在别的服务器节点超时完成前完成选举。 Log replication 一旦一个leader被选举,那它就开始接受client的请求,每一个client的请求都包含一个命令,这个命令会被 replicated state machines执行,leader将会把这个command append到日志中去,作为一个新的entry,然后用AppendEntries 分发到其它的服务器。 leader会永远的尝试去写入follower log entry,直到所有的log entry都被 写入。 leader决定什么时候日志被 commit,当大多数的服务器都复制了一份entry后,就会提交,也会提前之前的entries,论文中设计了两个重要的属性 如果不同日志中的两个Entry有一样的index跟term,那他们存的一个东西 如果不同日志中的两个entry有一样的index跟term,那他们之前的所有entry是相同的。 属性1保证了,在给定的term与index中只会创建一个entry,属性2保证了一致性的简单性。 如果follower发现leader发过来的index跟term在自己的log里没有,那么会拒绝这个新的entry。(因为在消息中包含了这条新的之前的index跟term,所以可以检测之前的一致性,如果之前的都不一致就根本不会append这个新的) 在Raft中,处理leader与follower的不一致性是通过强制把leader的log记录复制给follower来完成的,这意味着follower的log的冲突部分,会被完全覆盖。 为了使follwer的log保持一致,leader必须找到leader与follwer最近的一个一样的entry,然后把这个之后的log都发给follower。 leader对于每一个follower都维护了一个index,这个index是leader将要发给follower的下一个index,当一个leader上台后, 会把这个next index初始化为自己log中的最后一个index,如果有follower的记录与leader不一致,那么在下一次Append Entries RPC的一致性检查中失败。当这个调用失败后,leader将决定下一个next index是多少,最终,next index会在重试中到达leader与follower一致的地方。当RPC调用成功之后,leader会把之后的记录全发给follower,这样就follower就完成了与leader的一致性同步。 ...

August 30, 2020 · 1 min · linxy