1.互斥锁的实现过程很简单,mutex是一个类,首先我们要先创建出类对象 std::mutex mylock,然后在你需要锁的代码块前后加上mylock.lock()和mylock.unlock() ,就可以实现互斥锁的加锁和解锁了。可以具体实现可以看下面的代码
#include <iostream>
#include <thread>
#include <mutex>
void work1(int& sum, std::mutex& mylock) {
for (int i = 1; i < 5000; i++) {
mylock.lock();
sum += i;
mylock.unlock();
}
}
void work2(int& sum, std::mutex& mylock) {
for (int i = 5000; i <= 10000; i++) {
mylock.lock();
sum += i;
mylock.unlock();
}
}
int fun() {
int sum = 0;
for (int i = 1; i <= 10000; i++) {
sum += i;
}
return sum;
}
int main()
{
std::mutex mylock;
int ans = 0;
std::thread t1(work1, std::ref(ans), std::ref(mylock));
std::thread t2(work2, std::ref(ans), std::ref(mylock));
t1.join();
t2.join();
std::cout << "sum1 : " << ans << std::endl;
std::cout << "sum2 : " << fun() << std::endl;
return 0;
}
2.用lock_guard类模板
#include <iostream>
#include <thread>
#include <mutex>
void work1(int& sum, std::mutex& mylock) {
for (int i = 1; i < 5000; i++) {
std::lock_guard<std::mutex> mylock_guard(mylock);
sum += i;
}
}
void work2(int& sum, std::mutex& mylock) {
for (int i = 5000; i <= 10000; i++) {
std::lock_guard<std::mutex> mylock_guard(mylock);
sum += i;
}
}
int fun() {
int sum = 0;
for (int i = 1; i <= 10000; i++) {
sum += i;
}
return sum;
}
int main()
{
std::mutex mylock;
int ans = 0;
std::thread t1(work1, std::ref(ans), std::ref(mylock));
std::thread t2(work2, std::ref(ans), std::ref(mylock));
t1.join();
t2.join();
std::cout << "sum1 : " << ans << std::endl;
std::cout << "sum2 : " << fun() << std::endl;
return 0;
}
可以通过大括号来规定实现的范围。比如下面这样
{
std::lock_guard<std::mutex> mylockguard(mylock);
/*...
中间用来写需要加锁的内容
*/
}
3.c++线程安全的栈
/*
* threadsafe_stack.cpp
*
* Created on: Nov 30, 2017
* Author: clh01s@163.com
* 线程安全的栈
*/
#include <exception>
#include <iostream>
#include <mutex>
#include <stack>
#include <memory>
#include <string>
using namespace std;
struct empty_stack: exception
{
const char* what() const throw();
};
template<typename T>
class threadsafe_stack
{
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
lock_guard<mutex> lock(other.m);
data = other.data;
}
//禁止使用=
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value)
{
//调用锁
lock_guard<mutex> lock(m);
/* 调用data.push()可能会抛出异常
* 如果复制或者移动数据项抛出异常或
* 者不能分配足够的内存来扩展下层的
* 数据结构。
* 不管怎样,stack保证了它是安全的
* 因此这不是一个问题。
*/
cout<<"push value = "<<new_value<<endl;
data.push(move(new_value));
}
shared_ptr<T> pop()
{
lock_guard<mutex> lock(m);
/* 在函数pop()重载的第一种形式中
* 他的代码可能会抛出一个empty_stack
* 异常,但是没有做任何修改,因此它时安全的
*/
if(data.empty()) throw empty_stack();
/* 创建res可能会抛出异常
* 1.调用make_shared可能会抛出异常
* 因为它无法为新对象和需要引用计数的
* 内部数据分配内存。
* 2.复制构造函数或移动构造函数中返回
* 数据项被复制/移动到新分配的内存时也
* 可能会抛出异常。
* 这两种情况下c++运行库和标准库确保没
* 有内存泄露并且新对象被正确销毁。因为
* 你仍然没有修改下层的栈所以没有问题。
*/
shared_ptr<T> const res(
make_shared<T>(move(data.top())));
//调用data.pop()保证了不会抛出异常,因此pop()的重载是异常安全的
data.pop();
return res;
}
void pop(T& value)
{
lock_guard<mutex> lock(m);
if(data.empty()) throw empty_stack();
/* 这次于第一次时类似的,只不过这次是拷贝赋值
* 或移动赋值操作符抛出异常,而不是构造新对象
* 和一个shared_ptr实例抛出异常
*/
value = move(data.pop());
//这于上一个重载相同不会抛出异常
data.pop();
}
bool empty() const
{
lock_guard<mutex> lock(m);
return data.empty();
}
private:
stack<T> data;
mutable mutex m;
};
int main()
{
threadsafe_stack<string> a;
a.push("aa");
a.push("bb");
return 0;
}
4.使用层次锁来避免死锁
#include "iostream"
#include "stdexcept"
#include "thread"
#include "mutex"
#include "climits"
#include "thread_guard.h"
using namespace std;
class hierarchical_mutex {
private:
std::mutex internal_mutex;
std::mutex data_mutex;
unsigned long const hierarchy_value;
// 保存上一次的层次值,该锁不能重入,所以只需要一个简单数据类型来保存
unsigned long previous_hierarchy_value;
// 当前层次值
static thread_local unsigned long this_thread_hierarchy_value;
void check_for_hierarchy_violation()
{
// 当前线程锁定了更低等级的或者是同等级的锁
if (this_thread_hierarchy_value <= hierarchy_value)
{
throw std::logic_error("mutex hierarchy violated");
}
}
void update_hierarchy_value()
{
// 保存当前层次值
previous_hierarchy_value = this_thread_hierarchy_value;
// 改变当前层次值
this_thread_hierarchy_value = hierarchy_value;
}
public:
explicit hierarchical_mutex(unsigned long value)
:hierarchy_value(value),previous_hierarchy_value(0){}
void lock()
{
check_for_hierarchy_violation();
internal_mutex.lock();
lock_guard<std::mutex> lock(data_mutex);
update_hierarchy_value();
}
void unlock()
{
internal_mutex.unlock();
lock_guard<std::mutex> lock(data_mutex);
this_thread_hierarchy_value = previous_hierarchy_value;
}
bool try_lock()
{
check_for_hierarchy_violation();
if (!internal_mutex.try_lock())
return false;
lock_guard<std::mutex> lock(data_mutex);
update_hierarchy_value();
return true;
}
};
thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value = ULONG_MAX;
struct Data {
hierarchical_mutex m;
int data;
Data(unsigned long hierarchical, int data)
:m(hierarchical), data(data) {}
void swap(Data & d)
{
lock_guard<hierarchical_mutex> lock1(m);
std::chrono::seconds dura(1);
std::this_thread::sleep_for(dura);
lock_guard<hierarchical_mutex> lock2(d.m);
std::swap(d.data, data);
}
};
int main()
{
Data d1(10000,1), d2(1000,2);
{
thread_guard t1(thread([&] {
try
{
d1.swap(d2);
}
catch (const std::exception&)
{
cout << "operation not be permitted!" << endl;
}
}));
thread_guard t2(thread([&] {
try
{
d2.swap(d1);
}
catch (const std::exception&)
{
cout << "operation not be permitted!" << endl;
}
}));
}
cout << d1.data << endl;
system("pause");
return 0;
}