一:什么是分布式锁
1、定义
在分布式系统中,一个应用部署在多台机器当中,在某些场景 下,为了保证数据一致性,要求在同一时刻,同一任务只在一 个节点上运行,即保证某个行为在同一时刻只能被一个线程执行;在单机单进程多线程环境,通过锁很容易做到,比如 mutex、spinlock、信号量等;而在多机多进程环境中,此时就需要分布式锁来解决了。
2、什么类型的锁
我们要在分布式场景中实现互斥类型的锁,但是对于分布式方式,运行的结点很可能不在相同的机器和不同的网段中,因此节点之间需要通过socket通信。而对于互斥类型在同一时刻只允许一个执行体进入临界资源。
3、虚假唤醒问题
在多处理机上,pthread_cond_signal 的实现可能无法避免地唤醒多个阻塞在条件变量的线程。这样我们就碰到了虚假唤醒,因此为了避免这种情况。我们在每次被唤醒后要再次判断是否可以读取数据。下面我们讨论为什么会出现虚假唤醒问题。
首先线程一想通过pthread_cond_wait 进行阻塞等待在条件变量中,但是进行到第二步,这个锁被解开之后,正好线程二被唤醒,将这个条件变量的空余锁进行加锁操作,然而线程一要在那里阻塞等待这个锁的释放。
在线程二中,这时候条件变量的值发生了变化,,然后继续进行执行,试图唤醒线程三,当线程二条件变量的锁被释放,线程一继续使用这个锁,对条件变量进行加锁,这时候进行判断条件变量的值,发现这个value与之前的value不同了,因为线程二中进行++操作了,这样线程一无法进行休眠操作。这样线程三也就被线程二所唤醒。
对于这种问题该怎么解决呢?我们通过在程序中添加while循环,重复检查条件,比如队列是否为空,这样保证程序更加健壮。
//线程一
pthread_cond_wait(mutex, cond)
{
value = cond->value; /* 1 */
pthread_mutex_unlock(mutex); /* 2 */
pthread_mutex_lock(cond->mutex); /* 10 */
if (value == cond -> value) /* 11 */
{
me->next_cond = cond->waiter;
cond->waiter = me;
pthread_mutex_unlock(cond->mutex);
ubable_to_run(me); //线程三在这里休眠
}
else
{
pthread_mutex_unlock(cond->mutex); /* 12 */
}
pthread_mutex_lock(mutex); /* 13 */
}
//线程二
pthread_cond_signa(cond)
{
pthread_mutex_lock(cond->mutex); /* 3 */
cond->vallue++; /* 4 */
if (cond->waiter) /* 5 */
{
slleeper = cond->waiter; /* 6 */
cond->waiter = sleeper->next_cond; /* 7 */
able_to_run(sleeper); /* 8 */
}
pthread_mutex_unlock(cond->mutex); /* 9 */
}
二、分布式锁的特性
1、互斥性
我们通过在数据库中创建一张表,其中对于这个锁的标记设置为唯一标识,当我们对锁进行加锁,那么向数据库中插入一条读独属于它自己的标志,代表这个锁有进程正在使用,当我们解锁,需要在数据库中将这个锁的信息进行删除操作。
通过上面的操作,我们可以保证同时只允许一个持锁对象进入临界资源,而其他持锁对象要么等待,要么轮询检测是否能获取锁。
2、锁超时
允许持锁对象持锁最长时间,如果持锁对象宕机,我们可以使用外力进行解除锁定,方便其他持锁对象获取锁。
3、高可用性
所谓高可用性也就是在合理时间内得到合理的回复。那怎么实现呢?锁存储位置如果宕机,可能引发整个系统不可用,所以应该有备份存储位置和切换备份存储的机制。对于计算型那就开多个备份点,而对存储型也多个备份点加上主从切换。
4、容错性
如果锁存储的位置宕机,恰好锁丢失,能否正确处理。我们通过raft一致性算法和redlock进行一致性来解决(半数以上)。
对于分布式锁就讲到这里,感谢大家观看!https://xxetb.xetslk.com/s/2D96kH
标签:线程,Linux,mutex,pthread,cond,唤醒,分布式 From: https://blog.csdn.net/2301_76446998/article/details/141323458