当前位置 主页 > 服务器问题 > Linux/apache问题 >

    linux中各种锁机制的使用与区别详解

    栏目:Linux/apache问题 时间:2019-12-04 07:53

    前言:

    相信需要了解这方面的知识的小伙伴,已经基本对进程间通信和线程间通信有了一定了解。例如,进程间通信的机制之一:共享内存(在这里不做详解):多个进程可同时访问同一块内存。如果不对访问这块内存的临界区进行互斥或者同步,那么进程的运行很可能出现一些不可预知的错误和结果。

    接下来我们了解三种常见的Linux下的互斥操作—>锁。

    1.互斥锁(mutex)

    特点:对于读者和写者来说。只要有一方获取了锁,另一方则不能继续获取,进而执行临界区代码。

    创建锁:

    有两种方法创建互斥锁,静态方式和动态方式。POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER 来静态初始化互斥锁,

    方法如下:

    pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 

    在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。

    动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下:

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr) 

    其中mutexattr用于指定互斥锁属性(见下),如果为NULL则使用缺省属性。 pthread_mutex_destroy ()用于注销一个互斥锁,API定义如下:

    int pthread_mutex_destroy(pthread_mutex_t *mutex) 

    锁操作主要包括加锁pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个,不论哪种类型的锁,都不可能被两个不同的线程同时得到, 而必须等待解锁。对于普通锁和适应锁类型,解锁者可以是同进程内任何线程; 而检错锁则必须由加锁者解锁才有效,否则返回EPERM;对于嵌套锁,文档和实现要求必须由 加锁者解锁,但实验结果表明并没有这种限制,这个不同目前还没有得到解释。在同一进程中 的线程,如果加锁后没有解锁,则任何其他线程都无法再获得锁。

    int pthread_mutex_lock(pthread_mutex_t *mutex) 
    int pthread_mutex_unlock(pthread_mutex_t *mutex) 
    int pthread_mutex_trylock(pthread_mutex_t *mutex)

    pthread_mutex_trylock() 语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回 EBUSY而不是挂起等待。
    例如:单例模式下,线程安全的加锁:

    class SingleTon 
    { 
    public: 
    static SingleTon* getInstance() 
    { 
    pthread_mutex_lock(&mutex); 
    if(mpSingle == NULL) 
    { 
    mpSingleTon = new SingleTon(); 
    } 
    pthread_mutex_unlock(&mutex); 
    return mpSingleTon; 
    } 
    private: 
    SingleTon(){}; 
    ~SingleTon(){pthread_mutex_desttroy(&mutex,NULL);} 
    static pthread_mutex_t mutex; 
    static SingleTon * mpSingleTon; 
    } 
    pthread_mutex_t SingleTon::mutex = PTHREAD_MUTEX_INITIALIZER; 
    SingleTon * SingleTon::mpSingleTon = NULL;

    优点:

    由一块能够被多个进程共享的内存空间(一个对齐后的整型变量)组成;这个整型变量的值能够通过汇编语言调用CPU提供的原子操作指令来增加或减少,并且一个进程可以等待直到那个值变成正数。 的操作几乎全部在应用程序空间完成;只有当操作结果不 一致从而需要仲裁时,才需要进入操作系统内核空间执行。这种机制允许使用的锁定原语有非常高的执行效率:由于绝大多数 的操作并不需要在多个进程之间进行仲裁,所以绝大多数操作都可以在应用程序空间执行,而不需要使用(相对高代价的)内核系统调