文章目录
- 一、锁的原理
- 过程1:
- 过程2
- 过程3
- 过程4
- 二、 锁的简单封装
- 1.LockGuard.hpp
- 2.使用
- 1.正常锁的使用
- 2.使用封装后的
- 总结
一、锁的原理
为了实现互斥锁操作,大多数体系结构都提供了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.线程独立的资源:线程的栈和线程的硬件上下文