Buscar..


Introducción

Una de las cosas más difíciles de hacer en C y C ++ es la administración de recursos. Afortunadamente, en C ++, tenemos muchas maneras de diseñar el manejo de recursos en nuestros programas. Este artículo espera explicar algunos de los modismos y métodos utilizados para administrar los recursos asignados.

Adquisición de recursos es la inicialización

La adquisición de recursos es la inicialización (RAII) es un lenguaje común en la gestión de recursos. En el caso de la memoria dinámica, utiliza punteros inteligentes para llevar a cabo la gestión de recursos. Cuando se usa RAII, un recurso adquirido se otorga de inmediato a un puntero inteligente o administrador de recursos equivalente. Solo se puede acceder al recurso a través de este administrador, por lo que el administrador puede realizar un seguimiento de varias operaciones. Por ejemplo, std::auto_ptr libera automáticamente su recurso correspondiente cuando queda fuera del alcance o se elimina de otro modo.

#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

El principal problema de std::auto_ptr es que no se puede copiar sin transferir la propiedad:

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

Debido a estas extrañas semánticas de copia, std::auto_ptr no se puede usar en contenedores, entre otras cosas. La razón por la que hace esto es para evitar que se borre la memoria dos veces: si hay dos auto_ptrs con propiedad del mismo recurso, ambos intentan liberarla cuando se destruyen. La liberación de un recurso ya liberado generalmente puede causar problemas, por lo que es importante prevenirlo. Sin embargo, std::shared_ptr tiene un método para evitar esto y no transfiere la propiedad al copiar:

#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 y seguridad de rosca

Pueden surgir problemas cuando varios subprocesos intentan acceder a un recurso. Para un ejemplo simple, supongamos que tenemos un hilo que agrega uno a una variable. Para ello, primero lee la variable, le agrega una y luego la almacena de nuevo. Supongamos que inicializamos esta variable a 1, luego creamos dos instancias de este hilo. Una vez que ambos subprocesos terminan, la intuición sugiere que esta variable debería tener un valor de 3. Sin embargo, la siguiente tabla ilustra lo que podría salir mal:

Hilo 1 Hilo 2
Tiempo Paso 1 Lee 1 de la variable
Tiempo Paso 2 Lee 1 de la variable
Tiempo Paso 3 Agrega 1 más 1 para obtener 2
Tiempo Paso 4 Agrega 1 más 1 para obtener 2
Tiempo paso 5 Almacenar 2 en variable
Tiempo Paso 6 Almacenar 2 en variable

Como puede ver, al final de la operación, 2 está en la variable, en lugar de 3. La razón es que el Subproceso 2 leyó la variable antes de que el Subproceso 1 terminara de actualizarla. ¿La solución? Mutexes.

Un mutex (acrónimo de mut UAL ex conclusión) es un objeto de la gestión de recursos diseñado para resolver este tipo de problema. Cuando un hilo quiere acceder a un recurso, "adquiere" la exclusión mutua del recurso. Una vez que se termina de acceder al recurso, el hilo "libera" el mutex. Mientras se adquiere el mutex, todas las llamadas para adquirir el mutex no volverán hasta que se libere el mutex. Para entender mejor esto, piense en un mutex como una línea de espera en el supermercado: los hilos se alinean al tratar de adquirir el mutex y luego esperar a que los hilos por delante terminen, luego usar el recurso, luego salir del paso. línea liberando el mutex. Habría pandemonium completo si todos trataran de acceder al recurso a la vez.

C ++ 11

std::mutex es la implementación de C ++ 11 de un 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow