no_std runtime
- Rust kursu
- Uzman
- Ders 45/46
- 7 dk
no_std için minimal bir runtime yazarsın.
Bitirme görevi: no_std runtime
Gömülü sistemlerde işletim sistemi yoktur; görevleri çalıştıran küçük bir runtime'ı kendin yazarsın. Heap olmadan çalışabilmesi için görevler sabit kapasiteli bir dizide, fonksiyon işaretçisi olarak tutulur:
struct Calistirici {
gorevler: [Option<fn() -> u32>; 4],
adet: usize,
}
impl Calistirici {
const fn new() -> Self {
Self { gorevler: [None; 4], adet: 0 }
}
fn ekle(&mut self, g: fn() -> u32) -> Result<(), &'static str> {
let yer = self.gorevler.get_mut(self.adet).ok_or("kuyruk dolu")?;
*yer = Some(g);
self.adet += 1;
Ok(())
}
}const fn new, çalıştırıcının static olarak derleme anında kurulabilmesini sağlar.
Görevleri çalıştırmak
Çalıştırıcı kuyruktaki görevleri sırayla çağırır ve sonuçlarını toplar. Gerçek bir gömülü runtime'da (embassy gibi) görevler async'tir ve kesmelerle (interrupt) uyandırılır; temel fikir aynıdır:
impl Calistirici {
fn hepsini_calistir(&self) -> u32 {
self.gorevler.iter().flatten().map(|g| g()).sum()
}
}flatten, Option'lardan yalnızca Some olanları geçirir.
Uygulama Küçük runtime
Yukarıdaki Calistirici türünü new, ekle ve hepsini_calistir ile yaz. 1, 2 ve 3 döndüren üç görev ekle; N görev, toplam X yazdır.
Başlangıç kodu
fn main() {
// buraya yaz
}Örnek çözüm
struct Calistirici {
gorevler: [Option<fn() -> u32>; 4],
adet: usize,
}
impl Calistirici {
const fn new() -> Self {
Self { gorevler: [None; 4], adet: 0 }
}
fn ekle(&mut self, g: fn() -> u32) -> Result<(), &'static str> {
let yer = self.gorevler.get_mut(self.adet).ok_or("kuyruk dolu")?;
*yer = Some(g);
self.adet += 1;
Ok(())
}
fn hepsini_calistir(&self) -> u32 {
self.gorevler.iter().flatten().map(|g| g()).sum()
}
}
fn bir() -> u32 {
1
}
fn iki() -> u32 {
2
}
fn uc() -> u32 {
3
}
fn main() {
let mut c = Calistirici::new();
for g in [bir as fn() -> u32, iki, uc] {
c.ekle(g).unwrap();
}
println!("{} görev, toplam {}", c.adet, c.hepsini_calistir());
}Beklenen çıktı
3 görev, toplam 6
Soru ve cevaplar
Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.
1 Neden closure yerine <code>fn() -> u32</code> işaretçisi kullanıldı?
- Daha okunaklıdır
- Neden yok
- Boyutu sabittir ve heap ya da Box gerektirmez Doğru cevap
- Closure'lar no_std'de yoktur
Açıklama: Farklı closure türlerini tek dizide tutmak Box<dyn Fn> ister; yakalamasız fonksiyon işaretçisi bunu heap olmadan çözer.
2 Boşları atla
self.gorevler.iter().____().map(|g| g()).sum()
self.gorevler.iter().flatten().map(|g| g()).sum()
Açıklama: Option yineleyicisinde flatten yalnızca Some değerleri verir.
3 Parça ve rolü
| Kavram | Anlamı |
|---|---|
[Option<fn() -> u32>; 4] |
Sabit kuyruk |
const fn new |
Derleme anı kurulum |
get_mut(adet) |
Kapasite denetimi |
flatten |
Boş yerleri atlar |