Guide de concurrence C ++ std :: mutex

Ces articles sont tous des notes enregistrées après avoir lu le Grand Dieu, lien https://www.cnblogs.com/haippy/p/3284540.html

Mutex est également appelé exclusion mutuelle. En C ++ 11, les classes et fonctions liées à Mutex (y compris les types de verrous) et les fonctions sont déclarées dans le fichier d'en-tête <mutex>, donc si vous devez utiliser std :: mutex, vous devez inclure le < mutex> fichier d'en-tête.

Fichier d'en-tête <mutex>

Série Mutex

  • std :: mutex, la classe Mutex la plus basique.
  • std :: recursive_mutex, la classe Mutex récursive.
  • std :: time_mutex, la classe Mutex de synchronisation.
  • std :: recursive_timed_mutex, classe Mutex récursive chronométrée.

Classe de verrouillage

  • std :: lock_guard, lié à Mutex RAII, facilite les threads pour verrouiller le mutex.
  • std :: unique_lock, lié à Mutex RAII, facilite les threads pour verrouiller le mutex, mais fournit un meilleur contrôle de verrouillage et de déverrouillage.

Autres types

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

une fonction

  • std :: try_lock, essayez de verrouiller plusieurs mutex en même temps.
  • std :: lock peut verrouiller plusieurs mutex en même temps.
  • std :: call_once, si plusieurs threads doivent appeler une fonction en même temps, call_once peut garantir que plusieurs threads n'appellent la fonction qu'une seule fois.

std :: mutex

std :: mutex est le mutex le plus basique de C ++ 11. L'objet std :: mutex fournit la caractéristique de propriété exclusive, c'est-à-dire qu'il ne prend pas en charge le verrouillage récursif des objets std :: mutex, tandis que std :: recursive_lock Le mutex l'objet peut être verrouillé récursivement.

  • Le constructeur std :: mutex n'autorise pas la construction de copie, ni la copie de déplacement. L'objet mutex initialement généré est à l'état déverrouillé.
  • lock (), le thread appelant verrouille le mutex. Lorsque le thread appelle cette fonction, les trois situations suivantes se produisent: (1). Si le mutex n'est pas actuellement verrouillé, le thread appelant verrouille le mutex et le thread a le verrou jusqu'à ce que le déverrouillage soit appelé. (2). Si le mutex actuel est verrouillé par d'autres threads, le thread appelant en cours est bloqué. (3) .Si le mutex actuel est verrouillé par le thread appelant en cours, un blocage (blocage) se produira.
  • déverrouiller (), déverrouiller, libérer la propriété du mutex.
  • try_lock (), essayez de verrouiller le mutex, si le mutex est occupé par d'autres threads, le thread actuel ne sera pas bloqué. Les 3 situations suivantes se produisent également lorsqu'un thread appelle cette fonction, (1). Si le mutex actuel n'est pas occupé par d'autres threads, le thread verrouille le mutex jusqu'à ce que le thread appelle déverrouiller pour libérer le mutex. (2) Si le mutex actuel est verrouillé par d'autres threads, le thread appelant actuel renvoie false sans être bloqué. (3) .Si le mutex actuel est verrouillé par le thread appelant en cours, un blocage (blocage) se produira.

par exemple:

#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, comme std :: mutex, est aussi un objet qui peut être verrouillé, mais contrairement à std :: mutex, std :: recursive_mutex permet au même thread de verrouiller le mutex plusieurs fois (ie verrou récursif) pour obtenir plusieurs niveaux de propriété de l'objet mutex. Lorsque std :: recursive_mutex libère le mutex, vous devez appeler unlock () le même nombre de fois que la profondeur du niveau de verrouillage, qui peut être compris comme le nombre de lock () et de unlock ( ) Le nombre de fois est le même, sauf que les caractéristiques de std :: recursive_mutex sont à peu près les mêmes que celles de std :: mutex.

std :: time_mutex

std :: time_mutex a deux fonctions membres de plus que std :: mutex, try_lock_for (), try_lock_until ().

  • La fonction try_lock_for accepte une plage de temps, ce qui signifie que le thread sera bloqué s'il n'acquiert pas le verrou dans ce laps de temps (différent du try_lock () de std :: mutex, try_lock retournera directement false si le verrou est non acquis lors de son appel), Si d'autres threads libèrent le verrou pendant cette période, le thread peut acquérir le verrou sur le mutex. S'il expire (c'est-à-dire que le verrou n'est pas acquis dans le délai spécifié), false est renvoyé .

  • La fonction try_lock_until accepte un point dans le temps comme paramètre. Avant le moment spécifié, le thread est bloqué s'il n'acquiert pas le verrou. Si d'autres threads libèrent le verrou pendant cette période, le thread peut acquérir le verrou sur le mutex. Si Overtime (c'est-à-dire que le verrou n'est pas obtenu dans le délai spécifié), alors false est renvoyé.

Le petit exemple suivant illustre l'utilisation 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

Comme la relation entre std: recursive_mutex et std :: mutex, les caractéristiques de std :: recursive_timed_mutex peuvent également être dérivées de std :: timed_mutex, et vous pouvez vérifier les informations vous-même.

std :: lock_guard

Lié à Mutex RAII, il est pratique pour les threads de verrouiller le 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 :: unique_lock

Similaire à std :: lock_guard. Il y a des instructions détaillées dans un autre article.

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

Je suppose que tu aimes

Origine blog.csdn.net/qq_24649627/article/details/113727305
conseillé
Classement