【Linux】锁的简单封装以及原理解析

2023-12-13 21:40:45


一、锁的原理

为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的 总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期。

锁其实也属于共享资源,因为可以被所有线程看到,但锁的申请与销毁是具有原子性的,下面我们看一下原理

在这里插入图片描述

过程1:

在这里插入图片描述

过程2

在这里插入图片描述

过程3

在这里插入图片描述

过程4

在这里插入图片描述
本质:把一个共享的锁,让一个线程以一条汇编的方式,交换到自己的硬件上下文中

二、 锁的简单封装

1.LockGuard.hpp

class Mutex{
public:
Mutex(pthread_mutex_t *lock)
:lock_(lock){}

void Lock(){
    pthread_mutex_lock(lock_);
}

void Unlock(){
        pthread_mutex_unlock(lock_);
}

~Mutex(){}

private:
    pthread_mutex_t *lock_;
};




class LockGuard{//类似智能指针的玩法
//出了作用域自动析构
public:
LockGuard(pthread_mutex_t *lock)
:mutex_(lock)
{
mutex_.Lock();
}

~LockGuard(){
    mutex_.Unlock();
}
private :
Mutex mutex_;
};

2.使用

#include<iostream>
 #include<unistd.h>
 #include<pthread.h>
 #include<string>
 #include<vector>
 #include"LockGuard.hpp"
 using namespace std;

#define NUM 4

pthread_mutex_t lock;


class threadData{
public:
    threadData(int number){
        threadname="thread-"+to_string(number);
    }
public:
string threadname;

};

int ticket=300;


void *getTicket(void*args){
    threadData*td=static_cast<threadData*>(args);
    const char*name=td->threadname.c_str();

    while(true){
 
        pthread_mutex_lock(&lock);
        if(ticket>0){
            usleep(1000);
            printf("who=%s get ticket :%d \n ",name ,ticket);
            ticket--;
            pthread_mutex_unlock(&lock);
        }
        else {
            pthread_mutex_unlock(&lock);
            break;
        }
            
        usleep(13);

    }
    printf("%s.....quit",name);
    return nullptr;
}

int main(){
    vector<pthread_t> tids;
    vector<threadData *> thread_datas;
    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        threadData *td = new threadData(i);
        thread_datas.push_back(td);
        pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
        tids.push_back(tid);
    }


    for(auto thread:tids){
        pthread_join(thread,nullptr);
    }

    for (auto td:thread_datas){
        delete td;
    }

    return 0;
}

1.正常锁的使用

在这里插入图片描述

2.使用封装后的

在这里插入图片描述

总结

1.申请锁和释放锁本身就被设计成了原子性操作
2.当线程访问临界区的过程,对于其他线程是原子的(对于其他线程来讲,一个线程要么没有锁,要么释放锁)。
3.在临界区中,线程可以被切换,(在线程被切出去的时候,是持有锁被切走的,我不在期间,你们没有锁,照样不能访问临界资源!!!!)
4.线程独立的资源:线程的栈和线程的硬件上下文

文章来源:https://blog.csdn.net/m0_74774759/article/details/134975877
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。