C ++同時実行ガイドstd :: mutex

これらの記事はすべて、偉大な神を読んだ後に記録されたメモです。リンクhttps://www.cnblogs.com/haippy/p/3284540.html

ミューテックスは相互排他とも呼ばれます。C++ 11では、ミューテックス関連のクラス(ロックタイプを含む)と関数が<mutex>ヘッダーファイルで宣言されているため、std :: mutexを使用する必要がある場合は、<を含める必要があります。ミューテックス>ヘッダーファイル。

<mutex>ヘッダーファイル

ミューテックスシリーズ

  • std :: mutex、最も基本的なミューテックスクラス。
  • std :: recursive_mutex、再帰的ミューテックスクラス。
  • std :: time_mutex、タイミングミューテックスクラス。
  • std :: recursive_timed_mutex、時限再帰ミューテックスクラス。

ロッククラス

  • ミューテックスRAIIに関連するstd :: lock_guardは、スレッドがミューテックスをロックするのを容易にします。
  • ミューテックスRAIIに関連するstd :: unique_lockは、スレッドがミューテックスをロックするのを容易にしますが、より優れたロックおよびロック解除制御を提供します。

他のタイプ

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

関数

  • std :: try_lock、複数のミューテックスを同時にロックしてみてください。
  • std :: lockは、複数のミューテックスを同時にロックできます。
  • std :: call_once、複数のスレッドが同時に関数を呼び出す必要がある場合、call_onceは、複数のスレッドが関数を1回だけ呼び出すようにすることができます。

std :: mutex

std :: mutexは、C ++ 11の最も基本的なミューテックスです。std:: mutexオブジェクトは、排他的所有権の特性を提供します。つまり、std :: mutexオブジェクトの再帰的ロックをサポートしませんが、std :: recursive_lockはミューテックスです。オブジェクトは再帰的にロックできます。

  • コンストラクターstd :: mutexは、コピーの構築もコピーの移動も許可しません。最初に生成されたミューテックスオブジェクトはロック解除された状態です。
  • lock()、呼び出しスレッドはミューテックスをロックします。スレッドがこの関数を呼び出すと、次の3つの状況が発生します。(1)ミューテックスが現在ロックされていない場合、呼び出し元のスレッドはミューテックスをロックし、ロック解除が呼び出されるまでスレッドはロックを保持します。(2)現在のミューテックスが他のスレッドによってロックされている場合、現在の呼び出しスレッドはブロックされます。(3)現在のミューテックスが現在の呼び出しスレッドによってロックされている場合、デッドロック(デッドロック)が発生します。
  • ロック解除()、ロック解除、ミューテックスの所有権を解放します。
  • try_lock()、ミューテックスをロックしようとします。ミューテックスが他のスレッドによって占有されている場合、現在のスレッドはブロックされません。スレッドがこの関数を呼び出すと、次の3つの状況も発生します。(1)現在のミューテックスが他のスレッドによって占有されていない場合、スレッドはロック解除を呼び出してミューテックスを解放するまでミューテックスをロックします。(2)現在のミューテックスが他のスレッドによってロックされている場合、現在の呼び出しスレッドはブロックされずにfalseを返します。(3)現在のミューテックスが現在の呼び出しスレッドによってロックされている場合、デッドロック(デッドロック)が発生します。

例えば:

#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はstd :: mutexと同様にロックできるオブジェクトですが、std :: mutexとは異なり、std :: recursive_mutexでは同じスレッドがミューテックスを複数回ロック(つまり再帰ロック)して複数のレベルを取得できますstd :: recursive_mutexがミューテックスを解放するとき、ロックレベルの深さと同じ回数(lock()とunlock()の数として理解できるunlock()を呼び出す必要があります。 )std :: recursive_mutexの特性がstd :: mutexとほぼ同じであることを除いて、回数は同じです。

std :: time_mutex

std :: time_mutexには、std :: mutex、try_lock_for()、try_lock_until()よりも2つ多くのメンバー関数があります。

  • try_lock_for関数は時間範囲を受け入れます。つまり、この期間内にロックを取得しない場合、スレッドはブロックされます(std :: mutexのtry_lock()とは異なり、ロックが呼び出されたときに取得されない)、この期間中に他のスレッドがロックを解放すると、スレッドはミューテックスのロックを取得できます。タイムアウトした場合(つまり、指定された時間内にロックが取得されなかった場合)、falseが返されます。 。

  • try_lock_until関数は、ある時点をパラメーターとして受け入れます。指定された時点の前に、スレッドはロックを取得しない場合はブロックされます。この期間中に他のスレッドがロックを解放すると、スレッドはミューテックスのロックを取得できます。 。残業の場合(つまり、指定された時間内にロックが取得されない場合)、falseが返されます。

次の小さな例は、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

std:recursive_mutexとstd :: mutexの関係と同様に、std :: recursive_timed_mutexの特性もstd :: timed_mutexから導出でき、自分で情報を確認できます。

std :: lock_guard

ミューテックスRAIIに関連して、スレッドがミューテックスをロックすると便利です。

#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

std :: lock_guardに似ています。別の記事に詳細な手順があります。

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

おすすめ

転載: blog.csdn.net/qq_24649627/article/details/113727305