Lygiagretumas yra pagrindinis šiuolaikinio skaičiavimo aspektas, leidžiantis efektyviai panaudoti išteklius ir pagerinti našumą. Tačiau tai sukelia sudėtingumo, dėl kurio gali kilti subtilių ir sunkiai derinamų problemų. Šiame straipsnyje apžvelgiamos pagrindinės sąvokos ir įrankiai, kuriuos sistemų programuotojai turi suprasti, kad galėtų veiksmingai valdyti lygiagretumą.

Fonas

Šiuolaikinėje skaičiavimo aplinkoje gijos veikia vienu metu, nesvarbu, ar tai vieno branduolio, ar kelių branduolių procesorius. Šios gijos sąveikauja dalindamosi būsena, o teisingam atminties operacijų išdėstymo užtikrinimas yra labai svarbus teisingumui. Apsvarstykite paprastą pavyzdį, kai viena gija įrašo reikšmę ir nustato vėliavėlę, o kita gija laukia vėliavėlės prieš skaitydama reikšmę. Norint užtikrinti, kad vėliavėlė būtų nustatyta po reikšmės įrašymo, reikia atidžiai tvarkyti atminties operacijas.

int v; bool v_ready = false;

void threadA() {
    v = 42;
    v_ready = true;
}

void threadB() {
    while (!v_ready) { /* wait */ }
    const int my_v = v;
    // Do something with my_v...
}

Teisės ir tvarkos įgyvendinimas

Siekiant išvengti duomenų lenktynių ir užtikrinti teisingumą, programavimo kalbos, tokios kaip C ir C++, pateikia atominius tipus ir operacijas. Šie įrankiai padeda valdyti atminties operacijų tvarką gijose.

std::atomic_int v(0);
std::atomic_bool v_ready(false);

void threadA() {
    v = 42;
    v_ready = true;
}

void threadB() {
    while (!v_ready.load()) { /* wait */ }
    const int my_v = v.load();
    // Do something with my_v...
}

Atomiškumas

Atominės operacijos užtikrina, kad bendrinamų kintamųjų skaitymas ir rašymas būtų nedalomi. Tai apsaugo nuo nutrūkusių skaitymo ir rašymo, kuris gali atsirasti, kai kintamasis yra didesnis nei mašinos žodžio dydis.

std::atomic<int64_t> counter;

void increment() {
    counter.fetch_add(1, std::memory_order_relaxed);
}

Skaitymo-keitimo-rašymo operacijos

Skaitymo-keitimo-rašymo (RMW) operacijos yra būtinos sinchronizavimo primityvams įgyvendinti. Įprastos RMW operacijos apima keitimą, palyginimą ir apsikeitimą (CAS) ir parinkimą ir pridėjimą.

std::atomic<int> value;

int old_value = value.exchange(42);
if (value.compare_exchange_weak(expected, desired)) {
    // CAS succeeded
}

Atminties užsakymai

Atminties užsakymai apibrėžia apribojimus, kaip kompiliatorius ir aparatinė įranga gali pertvarkyti operacijas. Nuoseklios operacijos suteikia stipriausias užsakymo garantijas, užtikrinančias vieną bendrą visų operacijų užsakymą.

std::atomic<int> x(0), y(0);

void thread1() {
    x.store(1, std::memory_order_seq_cst);
    int val = y.load(std::memory_order_seq_cst);
}

void thread2() {
    y.store(1, std::memory_order_seq_cst);
    int val = x.load(std::memory_order_seq_cst);
}

Įsigyti ir išleisti

Įsigijimo ir išleidimo užsakymai suteikia vienpusės atminties kliūtis, užtikrinančias, kad operacijos kritinėje dalyje nebūtų pertvarkytos per barjerą.

std::atomic<bool> flag(false);
int data;

void producer() {
    data = 42;
    flag.store(true, std::memory_order_release);
}

void consumer() {
    while (!flag.load(std::memory_order_acquire)) { /* spin */ }
    // data is now visible
}

Atpalaiduotos operacijos

Ramios operacijos suteikia silpniausias užsakymo garantijas ir yra naudingos, kai nereikia atlikti specialaus užsakymo.

std::atomic<int> counter(0);

void increment() {
    counter.fetch_add(1, std::memory_order_relaxed);
}

Klaidingas bendrinimas ir talpyklos efektai

Talpyklos suderinamumo protokolai gali sukelti našumo kliūtis dėl klaidingo bendrinimo, kai nesusiję kintamieji turi tą pačią talpyklos eilutę.

struct RMLock {
    int readers;
    bool writer_flag;
    char padding(CACHE_LINE_SIZE - sizeof(int) - sizeof(bool));
};

Lakioji ir atominė sintezė

The volatile raktinis žodis nėra tinkamas lygiagretumo įrankis. Tai nesuteikia reikiamų užsakymo ir atomiškumo garantijų.

volatile int shared_var; // Incorrect for concurrency

Išvada

Lygiagretumas yra sudėtinga tema, tačiau pagrindinių atomiškumo, tvarkos ir sinchronizavimo sąvokų supratimas gali padėti sistemų programuotojams parašyti teisingą ir efektyvų lygiagretų kodą. Naudodami tinkamus įrankius ir metodus, programuotojai gali išvengti įprastų spąstų ir sukurti tvirtas lygiagrečias sistemas.

Papildomi ištekliai

Jei tekste radote klaidą, siųskite pranešimą autoriui pažymėdami klaidą ir paspausdami Ctrl-Enter.

Norėdami komentuoti, turite būti prisijungę.

Draugai: - Marketingo paslaugos - Teisinės konsultacijos - Skaidrių skenavimas - Fotofilmų kūrimas - Karščiausios naujienos - Ultragarsinis tyrimas - Saulius Narbutas - Įvaizdžio kūrimas - Veidoskaita - Nuotekų valymo įrenginiai -  Padelio treniruotės - Pranešimai spaudai -