Zoeken…


Invoering

Een van de moeilijkste dingen om te doen in C en C ++ is resource management. Gelukkig hebben we in C ++ veel manieren om resourcebeheer in onze programma's te ontwerpen. Dit artikel hoopt enkele van de uitdrukkingen en methoden te verklaren die worden gebruikt om toegewezen middelen te beheren.

Resource Acquisition is initialisatie

Resource Acquisition Is Initialization (RAII) is een veelgebruikt idioom in resource management. In het geval van dynamisch geheugen, gebruikt het slimme aanwijzers om resourcebeheer te bewerkstelligen. Wanneer u RAII gebruikt, wordt een verworven bron onmiddellijk eigendom van een slimme aanwijzer of een vergelijkbare bronbeheerder. De resource is alleen toegankelijk via deze manager, zodat de manager verschillende bewerkingen kan bijhouden. Bijvoorbeeld, std::auto_ptr bevrijdt automatisch de bijbehorende bron wanneer deze buiten bereik valt of anderszins wordt verwijderd.

#include <memory>
#include <iostream>
using namespace std;

int main() {
    {
        auto_ptr ap(new int(5)); // dynamic memory is the resource
        cout << *ap << endl; // prints 5
    } // auto_ptr is destroyed, its resource is automatically freed
}
C ++ 11

std::auto_ptr 's grootste probleem is dat het niet gekopieerd kan worden zonder eigendom over te dragen:

#include <memory>
#include <iostream>
using namespace std;

int main() {
    auto_ptr ap1(new int(5));
    cout << *ap1 << endl; // prints 5
    auto_ptr ap2(ap1); // copy ap2 from ap1; ownership now transfers to ap2
    cout << *ap2 << endl; // prints 5
    cout << ap1 == nullptr << endl; // prints 1; ap1 has lost ownership of resource
}

Vanwege deze rare kopie-semantiek kan std::auto_ptr onder andere niet in containers worden gebruikt. De reden hiervoor is om te voorkomen dat het geheugen twee keer wordt verwijderd: als er twee auto_ptrs die eigenaar zijn van dezelfde bron, proberen ze beide deze te bevrijden wanneer ze worden vernietigd. Het vrijmaken van een al vrijgegeven bron kan over het algemeen problemen veroorzaken, dus het is belangrijk om het te voorkomen. std::shared_ptr heeft echter een methode om dit te voorkomen, terwijl het eigendom niet wordt overgedragen tijdens het kopiëren:

#include <memory>
#include <iostream>
using namespace std;

int main() {
    shared_ptr sp2;
    {
        shared_ptr sp1(new int(5)); // give ownership to sp1
        cout << *sp1 << endl; // prints 5
        sp2 = sp1; // copy sp2 from sp1; both have ownership of resource
        cout << *sp1 << endl; // prints 5
        cout << *sp2 << endl; // prints 5
    } // sp1 goes out of scope and is destroyed; sp2 has sole ownership of resource
    cout << *sp2 << endl;        
} // sp2 goes out of scope; nothing has ownership, so resource is freed

Mutexen en draadveiligheid

Er kunnen problemen optreden wanneer meerdere threads toegang proberen te krijgen tot een bron. Stel voor een eenvoudig voorbeeld dat we een thread hebben die er een aan een variabele toevoegt. Het doet dit door eerst de variabele te lezen, er één aan toe te voegen en vervolgens weer op te slaan. Stel dat we deze variabele initialiseren op 1 en vervolgens twee exemplaren van deze thread maken. Nadat beide threads zijn voltooid, suggereert intuïtie dat deze variabele een waarde van 3 moet hebben. De onderstaande tabel illustreert echter wat er mis kan gaan:

Discussie 1 Discussie 2
Tijd Stap 1 Lees 1 van variabele
Tijd Stap 2 Lees 1 van variabele
Tijd Stap 3 Voeg 1 plus 1 toe om 2 te krijgen
Tijd Stap 4 Voeg 1 plus 1 toe om 2 te krijgen
Tijd Stap 5 Sla 2 op in variabele
Tijd Stap 6 Sla 2 op in variabele

Zoals u kunt zien, zit aan het einde van de bewerking 2 in de variabele in plaats van 3. De reden is dat Thread 2 de variabele heeft gelezen voordat Thread 1 klaar was met bijwerken. De oplossing? Mutexes.

Een mutex (portmanteau van wederzijdse ex- clusie) is een object voor resourcebeheer dat is ontworpen om dit soort problemen op te lossen. Wanneer een thread toegang wil hebben tot een bron, "verwerft" deze de mutex van de bron. Zodra het klaar is met toegang tot de bron, "laat" de thread de mutex los. Terwijl de mutex wordt verkregen, zullen alle oproepen om de mutex te verkrijgen niet terugkeren totdat de mutex is vrijgegeven. Om dit beter te begrijpen, denk aan een mutex als een wachtlijn in de supermarkt: de threads gaan in lijn door te proberen de mutex te verkrijgen en dan te wachten tot de threads voor hen klaar zijn, gebruik vervolgens de resource en stap dan uit regel door de mutex vrij te geven. Er zou een complete pandemonium zijn als iedereen onmiddellijk toegang zou krijgen tot de bron.

C ++ 11

std::mutex is de implementatie van een mutex door C ++ 11.

#include <thread>
#include <mutex>
#include <iostream>
using namespace std;

void add_1(int& i, const mutex& m) { // function to be run in thread
    m.lock();
    i += 1;
    m.unlock();
}

int main() {
    int var = 1;
    mutex m;

    cout << var << endl; // prints 1
    
    thread t1(add_1, var, m); // create thread with arguments
    thread t2(add_1, var, m); // create another thread
    t1.join(); t2.join(); // wait for both threads to finish
    
    cout << var << endl; // prints 3
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow