Sök…


Introduktion

En av de svåraste sakerna att göra i C och C ++ är resurshantering. Tack och lov har vi i C ++ många sätt att utforma resurshantering i våra program. Den här artikeln hoppas kunna förklara några av de idiomer och metoder som används för att hantera tilldelade resurser.

Resursförvärv är initialisering

Resource Acquisition Is Initialization (RAII) är ett vanligt formspråk i resurshantering. När det gäller dynamiskt minne använder den smarta pekare för att åstadkomma resurshantering. När du använder RAII ges en förvärvad resurs omedelbart äganderätt till en smart pekare eller motsvarande resurshanterare. Resursen nås endast via den här hanteraren, så chefen kan hålla reda på olika operationer. Till exempel frigör std::auto_ptr automatiskt motsvarande resurs när den faller utanför räckvidden eller på annat sätt raderas.

#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 huvudproblem är att det inte kan kopieras utan att överföra ägande:

#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
}

På grund av dessa konstiga std::auto_ptr kan std::auto_ptr inte användas i containrar, bland annat. Anledningen till att det gör detta är att förhindra att minnet auto_ptrs bort två gånger: om det finns två auto_ptrs äger samma resurs, försöker de båda frigöra det när de förstörs. Att frigöra en redan befriad resurs kan generellt orsaka problem, så det är viktigt att förhindra det. std::shared_ptr har emellertid en metod för att undvika detta utan att överföra äganderätt vid kopiering:

#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

Mutexes & gängesäkerhet

Problem kan inträffa när flera trådar försöker komma åt en resurs. För ett enkelt exempel, anta att vi har en tråd som lägger till en variabel. Det gör detta genom att först läsa variabeln, lägga till en i den och sedan lagra den tillbaka. Anta att vi initialiserar denna variabel till 1 och skapar sedan två instanser av den här tråden. Efter att båda trådarna har avslutats antyder intuitionen att denna variabel ska ha ett värde på 3. Tabellen nedan illustrerar dock vad som kan gå fel:

Tråd 1 Tråd 2
Tid Steg 1 Läs 1 från variabel
Tid Steg 2 Läs 1 från variabel
Tid Steg 3 Lägg till 1 plus 1 för att få 2
Tid Steg 4 Lägg till 1 plus 1 för att få 2
Tid Steg 5 Förvara 2 i variabel
Tid Steg 6 Förvara 2 i variabel

Som ni ser är 2 i operationens slut 2 i variabeln istället för 3. Anledningen är att tråd 2 läste variabeln innan tråd 1 gjordes för att uppdatera den. Lösningen? Mutexes.

En mutex (kappsäck av mut UAL ex slutsats) är en resurs förvaltningsobjekt för att lösa den här typen av problem. När en tråd vill komma åt en resurs "förvärvar" resursens mutex. När det är gjort med åtkomst till resursen "släpper" tråden mutex. Medan mutex förvärvas kommer alla samtal för att förvärva mutex inte tillbaka förrän mutex släpps. För att bättre förstå detta, tänk på en mutex som en väntelinje i snabbköpet: trådarna går i linje genom att försöka skaffa mutexen och sedan vänta på att trådarna framför dem ska slutföras, sedan använda resursen och sedan kliva ut ur rad genom att släppa mutex. Det skulle vara komplett pandemonium om alla försökte komma åt resursen på en gång.

C ++ 11

std::mutex är C ++ 11: s implementering av en mutex.

#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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow