• 互斥锁设计,有效的避免死锁


    下面一段摘自网络,我觉得这是非常好的。锁是理解非常有帮助。
    “为什么要加锁?加锁是为了防止不同的线程訪问同一共享资源造成混乱。
    打个例如:人是不同的线程,卫生间是共享资源。
    你在上洗手间的时候肯定要把门锁上吧。这就是加锁,仅仅要你在里面。这个卫生间就被锁了,仅仅有你出来之后别人才干用。

    想象一下假设卫生间的门没有锁会是什么样?

    什么是加锁粒度呢?所谓加锁粒度就是你要锁住的范围是多大。


    比方你在家上卫生间,你仅仅要锁住卫生间就能够了吧,不须要将整个家都锁起来不让家人进门吧,卫生间就是你的加锁粒度。
    如何才算合理的加锁粒度呢?
    事实上卫生间并不仅仅是用来上厕所的,还能够洗澡,洗手。这里就涉及到优化加锁粒度的问题。


    你在卫生间里洗澡,事实上别人也能够同一时候去里面洗手,仅仅要做到隔离起来就能够。假设马桶,浴缸,洗漱台都是隔开相对独立的,实际上卫生间能够同一时候给三个人使用。当然三个人做的事儿不能一样。这样就细化了加锁粒度,你在洗澡的时候仅仅要关上浴室的门,别人还是能够进去洗手的。

    假设当初设计卫生间的时候没有将不同的功能区域划分隔离开。就不能实现卫生间资源的最大化使用。这就是设计架构的重要性。”

    从上述知道,有一种情况就是,当你进了卫生间,锁上了门,这时你从窗户逃走了,从而造成卫生间永远被锁住了。

    这就是当中一种死锁。
    因此能够设想的就是,当我们从卫生间出来的时候(不管正常出来,还是飞出来,...),都能把锁打开。其他人就能进来。

    以下的代码就能实现这个功能。
    metux.h

    #ifndef MUTEX_LOCK_H
    #define MUTEX_LOCK_H
    
    #ifndef WIN32
    #include <windows.h>
    #endif
    
    #ifdef __unix
    #include <pthread.h>
    #endif // __unix
    
    
    class Mutex
    {
    public:
    	Mutex();
    	~Mutex();
    
    	void Lock();
    
    	void Unlock();
    
    private:
    	Mutex(const Mutex&);
    	void operator=(const Mutex&);
    
    #ifdef WIN32
    	CRITICAL_SECTION m_mutex;
    #endif // WIN32
    
    #ifdef __unix
    	pthread_mutex_t m_mutex;
    #endif // __unix	
    };
    
    
    class MutexLock
    {
    public:
    	explicit MutexLock(Mutex *mutex) :m_mutex(mutex)
    	{
    		m_mutex->Lock();
    	};
    	~MutexLock()
    	{ 
    		m_mutex->Unlock(); 
    	};
    
    private:
    	// 不同意复制
    	MutexLock(const MutexLock&);
    	void operator=(const MutexLock&);
    
    	Mutex *m_mutex;
    };
    
    
    #endif // !MUTEX_LOCK_H
    
    
    mutex.cpp
    #include "mutex.h"
    
    Mutex::Mutex()
    {
    #ifdef WIN32
    	InitializeCriticalSection(&m_mutex);
    #endif
    #ifdef __unix
    	pthread_mutex_init(&m_mutex, NULL);
    #endif // __unix
    }
    
    Mutex::~Mutex()
    {
    #ifdef WIN32
    	DeleteCriticalSection(&m_mutex);
    #endif
    	
    #ifdef __unix
    	pthread_mutex_destroy(&m_mutex);
    #endif // __unix
    }
    
    void Mutex::Lock()
    {
    #ifdef WIN32
    	EnterCriticalSection(&m_mutex);
    #endif
    #ifdef __unix
    	pthread_mutex_lock(&m_mutex);
    #endif // __unix
    }
    
    void Mutex::Unlock()
    {
    #ifdef WIN32
    	LeaveCriticalSection(&m_mutex);
    #endif
    #ifdef __unix
    	pthread_mutex_unlock(&m_mutex);
    #endif // __unix
    }
    
    
    
    測试
    Mutex mutex;
    
    void MutexTest()
    {
    	MutexLock l(&mutex);
    	static int  i = 0;
    	printf("i = %d
    ", i);
    	++i;
    }
    原理就是,当MutexLock生命周期结束时,会调用析构函数,从而能够实现每次从卫生间出来都能够解锁。当然你能够在MutexText加入大括号({})来约束MetexLock的生命同期。从而减小锁的粒度。
    这个设计不管是原理还是实现,还是蛮简单的。

    前提是你有这方面的经验,才会想到这样的实现方法。



    一年之后:
    时间:20150611
    近期想用C++ 11的里面的std::mutex取代原来须要定义各种系统的mutex,由于这样代码更加简洁。
    上述设计是之前看LevelDB源代码学来,认为挺好,于是分享出来。而今天改动代码时候发现事实上能够用宏定义。
    比如:
    #define MUTEX_LOCK()
    	m_mutex.lock(); 
    	{
    
    #define MUTEX_UNLOCK()
    	}
    	m_mutex.unlock();
    假设,仅仅使用#define MUTEX_LOCK。没有使用MUTEX_UNLOCK,编译的时候肯定会报错。非常明显,没有MUTEX_UNLOCK。括号是不匹配的。曾经的方法是。假设你忘记了写大括号来控制锁的粒度。那么非常可能要到函数结束的时候才会解锁。如今的方法不存在这样的问题。
    可是假设在MUTEX_LOCK 与 MUTEX_UNLOCK之间有return、goto等等待,毫无疑问,将是一个僵局。

    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    jquery 实现 点击按钮后倒计时效果,多用于实现发送手机验证码、邮箱验证码
    javascript 中的后退和前进到上下一页
    文件IO流完成文件的复制(复杂版本主要用来演示各种流的用途,不是最佳复制方案哦)
    int ,Intege,String 三者之间的转换
    servlet生成验证码代码
    jsp servlet 的 请求转发和重定向
    struts2
    SQL连接:内连接、外连接、交叉连接。
    今天参加了聚思力面试
    进程(Process)和线程(Thread)的关系和区别
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4741258.html
Copyright © 2020-2023  润新知