Suche…


Einführung

In C und C ++ ist das Ressourcenmanagement eine der schwierigsten Aufgaben. Zum Glück haben wir in C ++ viele Möglichkeiten, Ressourcenmanagement in unseren Programmen zu gestalten. Dieser Artikel soll einige der Redewendungen und Methoden erläutern, die zur Verwaltung der zugewiesenen Ressourcen verwendet werden.

Ressourcenakquisition ist Initialisierung

Die Ressourcenerfassung ist die Initialisierung (RAII) ist ein allgemeiner Ausdruck in der Ressourcenverwaltung. Im Fall von dynamischem Speicher verwendet es intelligente Zeiger , um das Ressourcenmanagement durchzuführen. Bei Verwendung von RAII wird eine erworbene Ressource sofort einem intelligenten Zeiger oder einem gleichwertigen Ressourcenmanager zugeordnet. Auf die Ressource kann nur über diesen Manager zugegriffen werden, sodass der Manager verschiedene Vorgänge verfolgen kann. Beispiel: std::auto_ptr die entsprechende Ressource automatisch frei, wenn sie außerhalb des Gültigkeitsbereichs liegt oder anderweitig gelöscht wird.

#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

Das Hauptproblem von std::auto_ptr ist, dass es nicht kopiert werden kann, ohne den Besitzer zu übertragen:

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

Aufgrund dieser seltsamen Kopiersemantik kann std::auto_ptr unter anderem nicht in Containern verwendet werden. Der Grund ist, dass das Löschen des Speichers zweimal verhindert wird: Wenn zwei auto_ptrs mit der gleichen Ressource vorhanden sind, versuchen beide, sie zu löschen, wenn sie zerstört werden. Das Freigeben einer bereits freigegebenen Ressource kann im Allgemeinen zu Problemen führen. Daher ist es wichtig, dies zu verhindern. std::shared_ptr hat jedoch eine Methode, um dies zu vermeiden, während beim Kopieren der Besitz nicht übertragen wird:

#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

Mutexe & Fadensicherheit

Probleme können auftreten, wenn mehrere Threads versuchen, auf eine Ressource zuzugreifen. Angenommen, wir haben einen Thread, der einer Variablen einen hinzufügt. Dazu liest man zuerst die Variable, fügt eine hinzu und speichert sie dann zurück. Angenommen, wir initialisieren diese Variable auf 1 und erstellen dann zwei Instanzen dieses Threads. Nachdem beide Threads abgeschlossen sind, schlägt die Intuition vor, dass diese Variable den Wert 3 haben sollte. Die folgende Tabelle veranschaulicht jedoch, was möglicherweise schief geht:

Faden 1 Faden 2
Zeitschritt 1 Lese 1 aus Variable
Zeitschritt 2 Lese 1 aus Variable
Zeitschritt 3 Addiere 1 plus 1, um 2 zu erhalten
Zeitschritt 4 Addiere 1 plus 1, um 2 zu erhalten
Zeitschritt 5 Speichern Sie 2 in Variable
Zeitschritt 6 Speichern Sie 2 in Variable

Wie Sie sehen, befindet sich am Ende der Operation die Variable 2 anstelle von 3. Der Grund ist, dass der Thread 2 die Variable gelesen hat, bevor der Thread 1 seine Aktualisierung durchgeführt hat. Die Lösung? Mutexe

Ein Mutex ( Kunstwort aus mut ual ex schluss) ist ein Objekt Ressourcenmanagement entwickelt , um diese Art von Problem zu lösen. Wenn ein Thread auf eine Ressource zugreifen möchte, "erhält" er den Mutex der Ressource. Sobald der Zugriff auf die Ressource abgeschlossen ist, "gibt" der Thread den Mutex frei. Während der Mutex erworben wird, kehren alle Aufrufe zum Erwerb des Mutex nicht zurück, bis der Mutex freigegeben wird. Um dies besser zu verstehen, stellen Sie sich einen Mutex als Warteschlange im Supermarkt vor: Die Fäden gehen in die Reihe, indem sie versuchen, den Mutex zu erhalten, und warten, bis die vor ihnen liegenden Fäden fertiggestellt sind, dann die Ressource nutzen und dann aussteigen Linie durch Freigabe des Mutex. Wenn alle versuchen, sofort auf die Ressource zuzugreifen, gäbe es ein komplettes Pandemium.

C ++ 11

std::mutex ist die Implementierung eines Mutex in 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow