Hacker News

Suprasti Std:Shared_mutex iš C++17

komentarai

8 min read Via www.cppstories.com

Mewayz Team

Editorial Team

Hacker News

Std::shared_mutex iš C++17 supratimas

std::shared_mutex, pristatytas C++17, yra sinchronizavimo primityvus, leidžiantis kelioms gijomis vienu metu laikyti bendrinamus (skaitymo) užraktus, tuo pačiu užtikrinant išskirtinę prieigą rašymo operacijoms. Jis išsprendžia vieną iš labiausiai paplitusių šiuolaikinio C++ lygiagretumo iššūkių, suteikdamas kūrėjams švarų, standartinį būdą įdiegti skaitytuvo ir rašymo įrenginio užrakinimą nesiekiant trečiųjų šalių bibliotekų ar konkrečios platformos API.

Kas tiksliai yra std::shared_mutex ir kodėl jis buvo įtrauktas į C++17?

Prieš C++17 kūrėjai, kuriems reikėjo skaitytuvo ir rašymo semantikos, turėjo pasikliauti konkrečiai platformai skirtais sprendimais, tokiais kaip pthread_rwlock_t POSIX sistemose arba SRWLOCK sistemoje Windows, arba naudojo trečiųjų šalių bibliotekas, pvz., „Boost“. C++17 standarto komitetas pripažino šią spragą ir įvedė std::shared_mutex į antraštę, kad ją būtų pašalinta tiesiogiai.

Pagrindinė idėja yra paprasta: daugelyje realaus pasaulio programų duomenys skaitomi daug dažniau nei įrašomi. Standartinis std::mutex nuosekliai sujungia visą prieigą (įskaitant skaitymus), o tai sukuria nereikalingas kliūtis. std::shared_mutex panaikina šį apribojimą, išskirdama du užrakinimo režimus:

  • Bendrinama (skaitymo) užraktas – gauta naudojant lock_shared(); Tai vienu metu gali turėti kelios gijos, todėl puikiai tinka skaitymui vienu metu.
  • Išskirtinis (rašymo) užraktas – gautas naudojant lock(); vienu metu tai gali turėti tik viena gija, o kol ji laikoma, neleidžiama naudoti bendrų užraktų.
  • std::shared_lock – RAII paketas, kuris iškviečia lock_shared() kūrimo metu ir unlock_shared() sunaikinimo metu, kad būtų išvengta išteklių nutekėjimo.
  • std::unique_lock / std::lock_guard – naudojamas su išskirtiniu režimu, užtikrinant, kad rašymo operacijos būtų visiškai apsaugotos ir saugios išimčių atveju.

Dėl šio dviejų režimų dizaino std::shared_mutex natūraliai tinka tokiems scenarijams kaip talpyklos, konfigūracijos registrai ir bet kokia duomenų struktūra, kai darbo krūvyje dominuoja skaitymai.

Kaip naudoti std::shared_mutex realiame kode su komentarais?

Kodo, kuriame naudojamas std::shared_mutex, komentarai yra ypač vertingi, nes lygiagretumo logika yra žinoma sunkiai pagrįsta. Gerai išdėstyti komentarai paaiškina, kodėl buvo pasirinktas tam tikras užrakto tipas, o tai labai sumažina riziką, kad būsimi prižiūrėtojai netyčia pradės duomenų lenktynes. Čia yra tipiškas modelis:

#include 
#include 
#include 

class ConfigRegistry {
    keičiamas std::shared_mutex mtx_; // apsaugo žemiau esantį žemėlapį
    std::netvarkomas_žemėlapis data_;

viešas:
    // Skaitymo kelias: kelios gijos gali tai iškviesti vienu metu
    std::string get(const std::string& key) const {
        std::shared_lock lock(mtx_); // bendras užraktas – saugus skaitymui vienu metu
        auto it = duomenys_.rasti(raktas);
        grąžinti != data_.end() ? it->antrasis : "";
    }

    // Rašymo kelias: reikalinga išskirtinė prieiga
    void set(const std::string& key, const std::string& val) {
        std::unikalus_užraktas(mtx_); // išskirtinis užraktas – blokuoja visus skaitytojus
        duomenys_[raktas] = val;
    }
};

Atkreipkite dėmesį, kaip komentarai paaiškina kiekvieno užrakto pasirinkimo tikslą, o ne tik pakartokite, ką daro kodas. Tai yra auksinis standartas: komentarai turi atsakyti į kodėl, o ne į . Raktinis žodis mutable, esantis mutex, leidžia get() paskelbti const, tačiau vis tiek gali būti užrakintas, įprastas ir idiomatinis šablonas.

Pagrindinė įžvalga: visada naudokite RAII užrakto apvalkalus (std::shared_lock, std::unique_lock) su std::shared_mutex – niekada nenaudokite lock() ir unlock(). Rankinis užrakinimas, kai yra išimčių, yra garantuotas kelias į aklavietę ir neapibrėžtą elgesį.

Kokios yra dažniausios klaidos dirbant su std::shared_mutex?

Net ir turint aiškių komentarų ir gerų ketinimų, std::shared_mutex turi subtilių spąstų, kurie suvilioja patyrusius kūrėjus. Pavojingiausias yra užrakto atnaujinimas: nėra integruoto būdo atnaujinti bendrinamą užraktą į išskirtinį užraktą prieš tai jo neatleidus. Bandant tai padaryti neatleidžiant, akimirksniu atsiduria aklavietė, nes gijoje yra bendrai naudojamas užraktas, kol laukiama išskirtinio užrakto, kuris niekada negali būti suteiktas tol, kol egzistuoja bendras užraktas, įskaitant tą, kurį ji turi.

💡 DID YOU KNOW?

Mewayz replaces 8+ business tools in one platform

CRM · Invoicing · HR · Projects · Booking · eCommerce · POS · Analytics. Free forever plan available.

Start Free →

Kita dažna klaida yra apsaugoti netinkamą detalumą. Kūrėjai kartais užrakina per plačiai, pažeidžiant skaitytojo ir rašymo modelio paskirtį, arba per siaurai, palikdami langus, kuriuose invariantai pažeidžiami tarp dviejų atskirų užraktų įsigijimų. Komentarai, kuriuose aprašomas saugomas kintamasis, o ne tik užrakintas kintamasis, padeda komandoms nuspręsti, ar kodo peržiūra yra teisinga.

Našumas taip pat gali jus nustebinti. Labai ginčytinose sistemose, kuriose yra daug įrašų, std::shared_mutex iš tikrųjų gali veikti blogiau nei paprastas std::mutex dėl papildomų apskaitos išlaidų. Visada profiliuokite prieš manydami, kad skaitytojo ir rašytojo užrakinimas yra grynasis laimėjimas.

Kaip std::shared_mutex galima palyginti su std::mutex ir kitomis alternatyvomis?

std::mutex yra paprastesnis, greičiau gaunamas, kai ginčas yra mažas, ir tinkamas, kai skaitymas ir rašymas vyksta maždaug vienodu dažniu. std::shared_mutex šviečia, kai nuskaitoma daug daugiau nei rašoma – 10:1 ar didesnis santykis yra pagrįsta nykščio taisyklė prieš svarstant perjungimą.

C++14 pristatė std::shared_timed_mutex, kuri prideda try_lock_shared_for() ir try_lock_shared_until() bandymams su laiku. C++17 std::shared_mutex atmeta laiko variantus, kad būtų lengviau įgyvendinti. Jei bendrinamame kelyje reikia užrakinti pagal laiką, std::shared_timed_mutex išlieka pasiekiamas ir abu tipai yra visiškai standartiniai.

Neužrakinamoms alternatyvoms std::atomic kartu su kruopščiu atminties išdėstymu kartais gali visiškai pakeisti paprastų vėliavėlių ar skaitiklių mutex, tačiau sudėtingų duomenų struktūrų atveju std::shared_mutex išlieka geriausiai skaitomu ir prižiūrimu sprendimu standartinėje bibliotekoje.

Dažniausiai užduodami klausimai

Ar std::shared_mutex gali sukelti badą?

Taip, gali. Jei nuolat atkeliauja naujų bendrai naudojamų užraktų laikiklių, išskirtinio užrakto prašytojas gali laukti neribotą laiką – tai klasikinė rašytojo bado problema. C++ standartas neįpareigoja konkrečios sąžiningumo politikos, todėl elgsena priklauso nuo įgyvendinimo. Praktiškai dauguma standartinių bibliotekos įdiegimų teikia pirmenybę laukiantiems išskirtiniams užraktams, kai jie yra eilėje, tačiau turėtumėte tai patikrinti savo konkrečioje įrankių grandinėje ir platformoje, jei gamyboje kyla problemų dėl bado.

Ar std::shared_mutex saugu naudoti su std::condition_variable?

std::condition_variable reikalauja std::unique_lock, todėl jis nėra tiesiogiai suderinamas su std::shared_mutex. Jei reikia palaukti, kol bus įvykdyta sąlyga, kol laikysite bendrinamą mutex, naudokite std::condition_variable_any, kuri veikia su bet kokiu „BasicLockable“ tipu, įskaitant std::shared_mutex, suporuotą su std::shared_lock.

Ar turėčiau pridėti komentarų kiekvieną kartą, kai naudoju std::shared_mutex?

Beniausiai pakomentuokite mutex deklaraciją, kad apibūdintumėte, kokius duomenis jis saugo ir kokius invariantus jis palaiko. Kiekvienoje užrakinimo svetainėje trumpas komentaras, paaiškinantis, kodėl buvo pasirinkta bendra, o ne išskirtinė prieiga, suteikia daug naudos kodo tikrintojams ir būsimiems prižiūrėtojams. Vienalaikio klaidos yra vienos iš sunkiausių atkuriamų ir ištaisytų klaidų, todėl investicija į aiškius, tikslius komentarus atsiperka daug kartų.


Sudėtingų sistemų valdymui – nesvarbu, ar tuo pačiu metu naudojamas C++ kodas, ar visa verslo operacija – reikia tinkamų įrankių ir aiškios struktūros. Mewayz yra 207 modulių verslo OS, kuria pasitiki daugiau nei 138 000 naudotojų, kad būtų suteiktas toks pat aiškumas rinkodaros, CRM, el. komercijos, analizės ir kt. srityse – visa tai vienoje platformoje nuo 19 USD per mėnesį. Nustokite žongliruoti daugybe atjungtų įrankių ir pradėkite vykdyti savo verslą tiksliai suprojektuota programine įranga. Išbandykite „Mewayz“ šiandien adresu app.mewayz.com ir sužinokite, kaip vieninga sistema pakeičia jūsų komandos darbą.

Try Mewayz Free

All-in-one platform for CRM, invoicing, projects, HR & more. No credit card required.

Start managing your business smarter today

Join 30,000+ businesses. Free forever plan · No credit card required.

Ready to put this into practice?

Join 30,000+ businesses using Mewayz. Free forever plan — no credit card required.

Start Free Trial →

Ready to take action?

Start your free Mewayz trial today

All-in-one business platform. No credit card required.

Start Free →

14-day free trial · No credit card · Cancel anytime