锁(mutex)使用(c++11、c++14、c++17)

 

新的C++版本提供了以下锁:

mutex

(C++11)

recursive_mutex

(C++11)

shared_mutex

(C++17)

timed_mutex

(C++11)

recursive_timed_mutex

(C++11)

shared_timed_mutex

(C++14)

 

  • 上述有timed字面值的锁对应没有timed字面值的锁多了两种操作(1. 可以指定请求锁等待的超时时间;2. 可以指定请求锁一直到某一个时刻)
  • 超时时间类型为std::chrono::duration
  • 时刻时间类型为std::chrono::time_point
  • lock_guard、unique_lock、scoped_lock、std::lock、std::try_lock 可使用 全部的锁
  • shared_lock 可使用 shared_mutexshared_timed_mutex
  • mutextimed_mutex不可循环锁
  • recursive_mutexrecursive_timed_mutex可循环锁
  • shared_mutexshared_timed_mutex为读写锁

提供了以下范围锁:

 

lock_guard

(C++11)

unique_lock

(C++11)

shared_lock

(C++14)

scoped_lock

(C++17)

 

 

 

 

 

  • lock_guard范围锁,简单,只有上锁和解锁两个操作,构造函数上锁,析构函数解锁
#include 
#include 
#include 
#include 

using std::cin;
using std::cout;
using std::endl;

template 
void lock_guard(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::lock_guard autolock(lock);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}


int main(int argc, char* argv[])
{
    ::lock_guard(); 
    ::lock_guard();
    ::lock_guard();
}

 

  • unique_lock范围锁,功能多一些,提供上锁,解锁,尝试取得锁,超时请求锁,同时也用来做写锁
#include 
#include 
#include 
#include 

using std::cin;
using std::cout;
using std::endl;

template 
void unique_lock(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

template 
void unique_lock_after_time() {
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock, std::chrono::milliseconds(1'000));
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

template 
void unique_lock_until_time() {
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock, std::chrono::time_point < std::chrono::high_resolution_clock >(std::chrono::milliseconds(1'000)));
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

int main(int argc, char* argv[])
{
    // 上锁和解锁操作,一直等待到获得锁
    ::unique_lock(); 
    ::unique_lock();
    ::unique_lock();
    ::unique_lock();
    ::unique_lock();
    ::unique_lock();

    // 上锁和解锁操作,在一定时间内等待锁,否则超时
    ::unique_lock_after_time();
    ::unique_lock_after_time();
    ::unique_lock_after_time();

    // 上锁和解锁操作,等待获得锁一直到某一个时间点,否则超时
    ::unique_lock_until_time();
    ::unique_lock_until_time();
    ::unique_lock_until_time();
}

 

  • scoped_lock范围锁,可同时锁住多个锁
#include 
#include 
#include 
#include 

using std::cin;
using std::cout;
using std::endl;

template 
void scoped_lock(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::scoped_lock autolock(lock);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

template 
void scoped_lock(){
	int i = 0;
	T lock;
	U lock2;
	auto fWThread = [&i, &lock, &lock2]() {
		for (int k = 0; k < 10; k++) {
			std::scoped_lock autolock(lock, lock2);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

template 
void scoped_lock(){
	int i = 0;
	T lock;
	U lock2;
	V lock3;
	auto fWThread = [&i, &lock, &lock2, &lock3]() {
		for (int k = 0; k < 10; k++) {
			std::scoped_lock autolock(lock, lock2, lock3);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

int main(int argc, char* argv[])
{
    // 上锁和解锁操作,一直等待到获得锁
    ::scoped_lock(); 
    ::scoped_lock();
    ::scoped_lock();

    // 上锁和解锁,同时对两个锁进行操作
    ::scoped_lock();
    ::scoped_lock();

    // 上锁和解锁,同时对三个锁进行操作
    ::scoped_lock();
    ::scoped_lock();


    // 同理,上锁和解锁,可同时对多个锁进行操作
}

 

  • shared_lock范围锁,读锁,读锁之间无互斥关系,不需要等待。常与unique_lock(作写锁)配合使用。
    • 只能用于shared_mutex和shared_timed_mutex
    • shared_lock只有在没有写锁的情况下才能获得锁,unique_lock只有在没有读锁的情况下才能获得锁
#include 
#include 
#include 
#include 

using std::cin;
using std::cout;
using std::endl;

template 
void share_lock() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock autolock(lock);
			int j = i;
			std::cout << std::this_thread::get_id() << " read: " << j << endl;
		}
	};
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock);
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread r1(fRThread);
	std::thread w1(fWThread);
	std::thread r2(fRThread);
	r1.join();
	r2.join();
	w1.join();
}

template 
void share_lock_until_time() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock autolock(lock, std::chrono::time_point < std::chrono::high_resolution_clock >(std::chrono::milliseconds(1'000)));
			int j = i;
			std::cout << std::this_thread::get_id() << " read: " << j << endl;
		}
	};
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock, std::chrono::time_point < std::chrono::high_resolution_clock >(std::chrono::milliseconds(1'000)));
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread r1(fRThread);
	std::thread w1(fWThread);
	std::thread r2(fRThread);
	r1.join();
	r2.join();
	w1.join();
}

template 
void share_lock_after_time() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock autolock(lock, std::chrono::milliseconds(1'000));
			int j = i;
			std::cout << std::this_thread::get_id() << " read: " << j << endl;
		}
	};
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock autolock(lock, std::chrono::milliseconds(1'000));
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread r1(fRThread);
	std::thread w1(fWThread);
	std::thread r2(fRThread);
	r1.join();
	r2.join();
	w1.join();
}

int main(int argc, char* argv[])
{
    // 上锁和解锁操作,一直等待到获得锁
    ::share_lock(); 

    // 上锁和解锁操作,在一定时间内等待锁,否则超时
    ::share_lock_after_time();

    // 上锁和解锁操作,等待获得锁一直到某一个时间点,否则超时
    ::share_lock_until_time();
}

提供了以下同时锁多个锁(不造成死锁):

lock

(C++11)

try_lock

(C++11)

 

 

 

std::lock: 同时给多个锁上锁

std::try_lock:尝试同时给多个锁上锁

注意:这两个方法并不会去释放锁,需要自己主动去释放

#include 
#include 
#include 
#include 

using std::cin;
using std::cout;
using std::endl;

template 
void lock(){
	int i = 0;
	T lock;
    T lock2;
    U lock3;
	auto fWThread = [&i, &lock, &lock2, &lock3]() {
		for (int k = 0; k < 10; k++) {
			std::lock(lock, lock2, lock3);
			std::lock_guard l1(lock, std::adopt_lock);// make sure lock is unlock finally
			std::lock_guard l2(lock2, std::adopt_lock);// make sure lock2 is unlock finally
			std::lock_guard l3(lock3, std::adopt_lock);// make sure lock3 is unlock finally
			int j = ++i;
			std::cout << std::this_thread::get_id() << " write: " << j << endl;
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

template 
void try_lock(){
	int i = 0;
	T lock;
    T lock2;
    U lock3;
	auto fWThread = [&i, &lock, &lock2, &lock3]() {
		for (int k = 0; k < 10; k++) {
            // -1 means success
			if (-1 == std::try_lock(lock, lock2, lock3)){
			    int j = ++i;
			    std::cout << std::this_thread::get_id() << " write: " << j << endl;
				lock.unlock();
				lock2.unlock();
				lock3.unlock();
            }
            else{
			    std::cout << std::this_thread::get_id() << " get lock failed" << endl;
            }   
		}
	};
	std::thread w1(fWThread);
	std::thread w2(fWThread);
	w1.join();
	w2.join();
}

int main(int argc, char* argv[])
{
    ::lock(); 
    ::try_lock(); 
}

提供了以下结构体指明要对锁做的操作:

defer_lock_t

(C++11)

try_to_lock_t

(C++11)

adopt_lock_t

(C++11)

 

 

 

以下分别是上面的常量实例化

defer_lock

(C++11)

try_to_lock

(C++11)

adopt_lock

(C++11)

 

 

 

它们用于指定std::lock_guard, std::unique_lock和std::shared_lock的锁定策略。

  • std::defer_lock: 不进行上锁操作
  • std::try_to_lock: 会尝试去获得锁,不一定会获得锁,会立即返回
  • std::adopt_lock: 会认为锁已经是上锁状态了。

如:   

std::mutex lock;
// 此处构造autolock时不会对lock上锁
std::unique_lock autolock(lock, std::defer_lock);
// 此处构造autolock时会尝试去获得锁,会立即返回
std::unique_lock autolock(lock, std::try_to_lock);
// 此处构造autolock时会假定lock已经上锁了
std::unique_lock autolock(lock, std::adopt_lock);

 

还提供了整个程序中只调用一次的接口:

once_flag

(C++11)

call_once

(C++11)

 

 

 

    once_flag用于call_once,once_flag标记是否被调用过。

        · 若被调用的函数执行过了,那么这个标记就会标记为已调用;

        · 若在调用的函数执行过程中抛出了异常,那么这个标记仍标记为未调用。

     call_once指定只需要调用一次的函数入口

#include 
#include 
#include 
 
std::once_flag flag1, flag2;
 
void simple_do_once()
{
    std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
 
void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n"; // this may appear more than once
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n"; // guaranteed once
}
 
void do_once(bool do_throw)
{
  try {
    std::call_once(flag2, may_throw_function, do_throw);
  }
  catch (...) {
  }
}
 
int main()
{
    std::thread st1(simple_do_once);
    std::thread st2(simple_do_once);
    std::thread st3(simple_do_once);
    std::thread st4(simple_do_once);
    st1.join();
    st2.join();
    st3.join();
    st4.join();
 
    std::thread t1(do_once, true);
    std::thread t2(do_once, true);
    std::thread t3(do_once, false);
    std::thread t4(do_once, true);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

/*
Simple example: called once
throw: call_once will retry
throw: call_once will retry
Didn't throw, call_once will not attempt again
*/

 

你可能感兴趣的:(c++,c++,锁,mutex)