C++
Embedded
Gömülü kısıtlarla optimize edilmiş kod yazarsın.
volatile ve bellek eşlemeli I/O
Bellek eşlemeli I/O (MMIO), donanım kayıtlarının normal bellek adreslerinde görünmesidir. Bir kaydı okumak için o adresteki değeri okuruz. volatile anahtar kelimesi derleyiciye "her okumada bellekten oku, önbelleğe alma" der.
Örnek: volatile std::uint32_t* reg bir donanım kaydına işaret eder. *reg = 64; yazma, *reg okuma yapar. Derleyici bu erişimleri atlayamaz. Bu derste volatile std::uint32_t değişkenini bir sahte kayıt olarak kullanıp MMIO desenini öğreneceğiz.
Derleyici optimizasyonu ve volatile
Derleyici en iyileyici (optimizer), bir değişkeni birden çok kez okuduğunda önceki sonucu yeniden kullanabilir. Normal bir değişkende bu güvenlidir; çünkü değer program tarafından değişmedikçe aynı kalır. Donanım kaydında ise değer program dışında değişebilir; önbelleğe alınmış okuma yanlış olur.
volatile bu optimizasyonu kapatır. Her *reg okuması belleğe gider. Bu dersin örneğinde sahte kaydı 64 değeriyle yazar, sonra geri okuruz. Sonuç 64 olur; volatile sayesinde okuma atlanmaz.
Uygulama readRegister ve writeRegister metodlarını ekle
Önceki dersin çözümünü al (Engine sınıfında parallelSum var). Engine sınıfının public: bölümüne iki statik metot ekle: static std::uint32_t readRegister(volatile std::uint32_t* reg) gövdesi return *reg;, static void writeRegister(volatile std::uint32_t* reg, std::uint32_t value) gövdesi *reg = value;. main içinde parallelSum çağrısından sonra şunları ekle: volatile std::uint32_t reg = 0;, Engine::writeRegister(®, 64);, std::cout << std::endl << Engine::readRegister(®);. #include <cstdint> gereklidir.
Örnek çözümü göster
#include <iostream>
#include <atomic>
#include <thread>
#include <cstdint>
class Engine {
public:
static const int Version = 1;
static int parallelSum() {
std::atomic<int> total{0};
std::thread t1([&]() { for (int i = 1; i <= 4; ++i) total += i; });
std::thread t2([&]() { for (int i = 5; i <= 8; ++i) total += i; });
t1.join();
t2.join();
return total.load();
}
static std::uint32_t readRegister(volatile std::uint32_t* reg) {
return *reg;
}
static void writeRegister(volatile std::uint32_t* reg, std::uint32_t value) {
*reg = value;
}
};
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << "Hazır" << std::endl;
std::cout << Factorial<5>::value << std::endl;
std::cout << Engine::parallelSum() << std::endl;
volatile std::uint32_t reg = 0;
Engine::writeRegister(®, 64);
std::cout << Engine::readRegister(®);
return 0;
}
Kendini test et
-
Kayıt işaretçisini tamamla
std::uint32_t readRegister(volatile std::uint32_t* ____) { return *reg; }
Cevabı göster
std::uint32_t readRegister(volatile std::uint32_t* reg) { return *reg; }
-
Parçayı rolüne eşle
- volatile
- Optimizasyonu kapatır
- std::uint32_t*
- Kayıt işaretçisi
- *reg = 64
- Kayda yazma
- *reg
- Kayıttan okuma
-
volatile anahtar kelimesi ne işe yarar?
volatile std::uint32_t* reg;
- Değişkeni sabit yapar
- Derleyiciye okumayı atlamamasını söyler
- Değişkeni otomatik sıfırlar
- Değişkeni iş parçacığı yerel yapar
Cevabı göster
Derleyiciye okumayı atlamamasını söyler — volatile her okumayı belleğe zorlar; önbelleğe almaz.
Sıradaki ders: Birleştirme