锁(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)

 

提供了以下范围锁:

 

lock_guard

(C++11)

unique_lock

(C++11)

shared_lock

(C++14)

scoped_lock

(C++17)

 

 

 

 

 

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

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

template <class T>
void lock_guard(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::lock_guard<T> 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<std::mutex>(); 
    ::lock_guard<std::recursive_mutex>();
    ::lock_guard<std::timed_mutex>();
}

 

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

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

template <class T>
void unique_lock(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock<T> 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 <class T>
void unique_lock_after_time() {
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock<T> 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 <class T>
void unique_lock_until_time() {
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::unique_lock<T> 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<std::mutex>(); 
    ::unique_lock<std::recursive_mutex>();
    ::unique_lock<std::timed_mutex>();
    ::unique_lock<std::recursive_timed_mutex>();
    ::unique_lock<std::shared_mutex>();
    ::unique_lock<std::shared_timed_mutex>();

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

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

 

#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>

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

template <class T>
void scoped_lock(){
	int i = 0;
	T lock;
	auto fWThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::scoped_lock<T> 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 <class T, class U>
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<T, U> 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 <class T, class U, class V>
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<T, U, V> 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<std::mutex>(); 
    ::scoped_lock<std::recursive_mutex>();
    ::scoped_lock<std::timed_mutex>();

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

    // 上锁和解锁,同时对三个锁进行操作
    ::scoped_lock<std::mutex, std::mutex, std::mutex>();
    ::scoped_lock<std::mutex, std::recursive_mutex, std::timed_mutex>();


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

 

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

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

template <class T>
void share_lock() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock<T> 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<T> 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 <class T>
void share_lock_until_time() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock<T> 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<T> 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 <class T>
void share_lock_after_time() {
	int i = 0;
	T lock;
	auto fRThread = [&i, &lock]() {
		for (int k = 0; k < 10; k++) {
			std::shared_lock<T> 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<T> 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<std::shared_mutex>(); 

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

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

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

lock

(C++11)

try_lock

(C++11)

 

 

 

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

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

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

#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <thread>

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

template <class T, class U>
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<T> l1(lock, std::adopt_lock);// make sure lock is unlock finally
			std::lock_guard<T> l2(lock2, std::adopt_lock);// make sure lock2 is unlock finally
			std::lock_guard<U> 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 <class T, class U>
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<std::mutex, std::recursive_mutex>(); 
    ::try_lock<std::mutex, std::recursive_mutex>(); 
}

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

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<std::mutex> autolock(lock, std::defer_lock);
// 此处构造autolock时会尝试去获得锁,会立即返回
std::unique_lock<std::mutex> autolock(lock, std::try_to_lock);
// 此处构造autolock时会假定lock已经上锁了
std::unique_lock<std::mutex> autolock(lock, std::adopt_lock);

 

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

once_flag

(C++11)

call_once

(C++11)

 

 

 

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

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

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

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

#include <iostream>
#include <thread>
#include <mutex>
 
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
*/

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值