Guía de concurrencia de C ++ std :: mutex

Todos estos artículos son notas registradas después de leer al Gran Dios, enlace https://www.cnblogs.com/haippy/p/3284540.html

Mutex también se llama exclusión mutua. En C ++ 11, las clases y funciones relacionadas con Mutex (incluidos los tipos de bloqueo) y las funciones se declaran en el archivo de encabezado <mutex>, por lo que si necesita usar std :: mutex, debe incluir el < mutex> archivo de encabezado.

<mutex> archivo de encabezado

Serie mutex

  • std :: mutex, la clase Mutex más básica.
  • std :: recursive_mutex, la clase recursiva Mutex.
  • std :: time_mutex, la clase de temporización Mutex.
  • std :: recursive_timed_mutex, clase Mutex recursiva temporizada.

Clase de bloqueo

  • std :: lock_guard, relacionado con Mutex RAII, facilita los subprocesos para bloquear el mutex.
  • std :: unique_lock, relacionado con Mutex RAII, facilita los subprocesos para bloquear el mutex, pero proporciona un mejor control de bloqueo y desbloqueo.

Otros tipos

  • std :: once_flag
  • std :: adopt_lock_t
  • std :: defer_lock_t
  • std :: try_to_lock_t

función

  • std :: try_lock, intente bloquear múltiples mutex al mismo tiempo.
  • std :: lock puede bloquear múltiples mutex al mismo tiempo.
  • std :: call_once, si varios subprocesos necesitan llamar a una función al mismo tiempo, call_once puede garantizar que varios subprocesos llamen a la función solo una vez.

std :: mutex

std :: mutex es el mutex más básico en C ++ 11. El objeto std :: mutex proporciona la característica de propiedad exclusiva, es decir, no admite el bloqueo recursivo de objetos std :: mutex, mientras que std :: recursive_lock El mutex El objeto se puede bloquear de forma recursiva.

  • El constructor, std :: mutex no permite la construcción de copias, ni mover copia El objeto mutex generado inicialmente está en el estado desbloqueado.
  • lock (), el hilo de llamada bloqueará el mutex. Cuando el hilo llama a esta función, ocurrirán las siguientes tres situaciones: (1) Si el mutex no está bloqueado actualmente, el hilo que llama bloquea el mutex y el hilo tiene el bloqueo hasta que se llama a unlock. (2) Si el mutex actual está bloqueado por otros subprocesos, el subproceso de llamada actual se bloquea. (3) Si el mutex actual está bloqueado por el hilo de llamada actual, se producirá un interbloqueo (interbloqueo).
  • desbloquear (), desbloquear, liberar la propiedad del mutex.
  • try_lock (), intente bloquear el mutex, si el mutex está ocupado por otros subprocesos, el subproceso actual no se bloqueará. Las siguientes 3 situaciones también ocurren cuando un subproceso llama a esta función, (1) Si el mutex actual no está ocupado por otros subprocesos, el subproceso bloquea el mutex hasta que el subproceso llama a desbloquear para liberar el mutex. (2) Si el mutex actual está bloqueado por otros subprocesos, el subproceso de llamada actual devuelve falso sin ser bloqueado. (3) Si el mutex actual está bloqueado por el hilo de llamada actual, se producirá un interbloqueo (interbloqueo).

por ejemplo:

#include <iostream>         // std::cout
#include <thread>            // std::thread
#include <mutex>            // std::mutex

volatile int counter(0);     // non-atomic counter
std::mutex mtx;                // locks access to counter

void attempt_10k_increases() {
    
    
    for (int i=0; i<10000; ++i) {
    
    
        if (mtx.try_lock()) {
    
                // only increase if currently not locked:
            ++counter;
            mtx.unlock();
        }
    }
}

int main () {
    
    
    std::thread threads[10];
    for (int i=0; i<10; ++i) {
    
    
		threads[i] = std::thread(attempt_10k_increases);
	}
        
    for (auto& th : threads) {
    
    
		th.join();
	}
    std::cout << counter << " successful increases of the counter.\n";

    return 0;
}

std :: recursive_mutex

std :: recursive_mutex, como std :: mutex, también es un objeto que se puede bloquear, pero a diferencia de std :: mutex, std :: recursive_mutex permite que el mismo hilo bloquee el mutex varias veces (es decir, bloqueo recursivo) para obtener múltiples niveles de propiedad del objeto mutex. Cuando std :: recursive_mutex libera el mutex, debe llamar a unlock () la misma cantidad de veces que la profundidad del nivel de bloqueo, que puede entenderse como el número de bloqueo () y desbloqueo ( ) El número de veces es el mismo, excepto que las características de std :: recursive_mutex son aproximadamente las mismas que std :: mutex.

std :: time_mutex

std :: time_mutex tiene dos funciones miembro más que std :: mutex, try_lock_for (), try_lock_until ().

  • La función try_lock_for acepta un rango de tiempo, lo que significa que el hilo será bloqueado si no adquiere el bloqueo dentro de este período de tiempo (diferente del try_lock () de std :: mutex, try_lock devolverá directamente falso si el bloqueo es no se adquiere cuando se llama), si otros subprocesos liberan el bloqueo durante este período, el subproceso puede adquirir el bloqueo en el mutex. Si se agota el tiempo de espera (es decir, el bloqueo no se adquiere dentro del tiempo especificado), se devuelve falso .

  • La función try_lock_until acepta un punto en el tiempo como parámetro. Antes del momento especificado, el subproceso se bloquea si no adquiere el bloqueo. Si otros subprocesos liberan el bloqueo durante este período, el subproceso puede adquirir el bloqueo en el mutex Si las horas extraordinarias (es decir, el bloqueo no se obtiene dentro del tiempo especificado), se devuelve falso.

El siguiente pequeño ejemplo ilustra el uso de std :: time_mutex:

#include <iostream>       // std::cout
#include <chrono>         // std::chrono::milliseconds
#include <thread>          // std::thread
#include <mutex>          // std::timed_mutex

std::timed_mutex mtx;

void fireworks() {
    
    
	// waiting to get a lock: each thread prints "-" every 200ms:
	while (!mtx.try_lock_for(std::chrono::milliseconds(200))) {
    
    
		std::cout << "-";
	}
	// got a lock! - wait for 1s, then this thread prints "*"
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	std::cout << "*\n";
	mtx.unlock();
}

int main ()
{
    
    
	std::thread threads[10];
	// spawn 10 threads:
	for (int i=0; i<10; ++i) {
    
    
		threads[i] = std::thread(fireworks);
	}


	for (auto& th : threads) {
    
    
		th.join();
	}

	return 0;
}

std :: recursive_timed_mutex

Al igual que la relación entre std: recursive_mutex y std :: mutex, las características de std :: recursive_timed_mutex también se pueden derivar de std :: timed_mutex, y puede verificar la información usted mismo.

std :: lock_guard

En relación con Mutex RAII, es conveniente que los subprocesos bloqueen el mutex.

#include <iostream>        // std::cout
#include <thread>           // std::thread
#include <mutex>           // std::mutex, std::lock_guard
#include <stdexcept>     // std::logic_error

std::mutex mtx;

void print_even (int x) {
    
    
    if (x%2==0) std::cout << x << " is even\n";
    else throw (std::logic_error("not even"));
}

void print_thread_id (int id) {
    
    
    try {
    
    
        // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
        std::lock_guard<std::mutex> lck (mtx);
        print_even(id);
    }
    catch (std::logic_error&) {
    
    
        std::cout << "[exception caught]\n";
    }
}

int main ()
{
    
    
    std::thread threads[10];
    // spawn 10 threads:
    for (int i=0; i<10; ++i)
        threads[i] = std::thread(print_thread_id,i+1);

    for (auto& th : threads) th.join();

    return 0;
}

std :: bloqueo_unico

Similar a std :: lock_guard. Hay instrucciones detalladas en otro artículo.

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::unique_lock

std::mutex mtx;           // mutex for critical section

void print_block (int n, char c) {
    
    
    // critical section (exclusive access to std::cout signaled by lifetime of lck):
    std::unique_lock<std::mutex> lck (mtx);
    for (int i=0; i<n; ++i) {
    
    
        std::cout << c;
    }
    std::cout << '\n';
}

int main ()
{
    
    
    std::thread th1 (print_block,50,'*');
    std::thread th2 (print_block,50,'$');

    th1.join();
    th2.join();

    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/qq_24649627/article/details/113727305
Recomendado
Clasificación