Multithreading 什么';死锁和活锁的区别是什么?

Multithreading 什么';死锁和活锁的区别是什么?,multithreading,pthreads,deadlock,livelock,Multithreading,Pthreads,Deadlock,Livelock,有人能举例说明一下(代码)死锁和活锁之间的区别吗?摘自: 在并发计算中,死锁是一种状态,其中一组操作的每个成员都在等待其他成员释放锁 活锁类似于死锁, 除了 livelock中涉及的进程 关于一个人的不断变化 另一个,没有进展。活锁是 资源匮乏的特例; 一般定义仅说明 一个特定的过程不是 进步 一个真实的例子 当两个人相遇时就会发生活锁 在狭窄的走廊里,每个人都在尝试 礼貌地移到一边让别人进来 另一个过去了,但是他们结束了 摇摆不定 取得任何进展,因为他们都 以相同的方式在同一位置重复移动 同时

有人能举例说明一下(代码)死锁和活锁之间的区别吗?

摘自:

在并发计算中,死锁是一种状态,其中一组操作的每个成员都在等待其他成员释放锁

活锁类似于死锁, 除了 livelock中涉及的进程 关于一个人的不断变化 另一个,没有进展。活锁是 资源匮乏的特例; 一般定义仅说明 一个特定的过程不是 进步

一个真实的例子 当两个人相遇时就会发生活锁 在狭窄的走廊里,每个人都在尝试 礼貌地移到一边让别人进来 另一个过去了,但是他们结束了 摇摆不定 取得任何进展,因为他们都 以相同的方式在同一位置重复移动 同时

Livelock是一种风险 一些用于检测和检测的算法 从死锁中恢复。如果超过 一个进程采取行动,即死锁 检测算法可以重复使用 触发。这可以通过以下方式避免: 确保只有一个流程(已选择) 随机或按优先级)采取行动

死锁 死锁是任务等待的一种情况 无限期地等待永远无法实现的条件 满意的 -任务声明对共享资源的独占控制 资源 -任务在等待其他任务时保留资源 将要释放的资源 -不能强制任务重新使用资源 -存在循环等待条件

LIVELOCK 当两个或多个 更多的任务依赖并使用一些 导致循环依赖的资源 这些任务继续的条件 永远运行,从而阻止所有较低的 运行的优先级任务(这些 优先级较低的任务会遇到一种情况 被称为饥饿)

一个线程经常响应另一个线程的操作。如果 另一个线程的动作也是对另一个线程动作的响应 线程,则可能会产生livelock

与死锁一样,livelocked线程无法取得进一步的进展。但是,线程没有被阻塞——它们只是忙于相互响应而无法继续工作。这相当于两个人试图在走廊里互相超越:阿尔方斯向左移动让加斯顿通过,而加斯顿向右移动让阿尔方斯通过。看到他们仍在互相阻挡,阿尔方斯向右移动,加斯顿向左移动。他们还在互相阻拦,等等

livelockdeadlock之间的主要区别在于线程不会被阻塞,相反,它们会尝试不断地相互响应

在该图像中,两个圆(线程或进程)将通过向左和向右移动来尝试为另一个圆提供空间。但他们不能再往前走了


这里的所有内容和示例都来自

操作系统:内部和设计原则
威廉·斯泰林斯
8º版

死锁:两个或多个进程无法继续进行的情况,因为每个进程都在等待另一个进程执行某项操作

例如,考虑两个过程P1和P2,以及两个资源R1和R2。假设每个进程都需要访问这两种资源才能执行其部分功能。然后可能出现以下情况:操作系统将R1分配给P2,将R2分配给P1。每个进程都在等待两个资源中的一个。在获得之前,两者都不会释放它已经拥有的资源 另一个资源,并执行需要这两个资源的功能。两个 进程陷入僵局

Livelock:两个或多个进程在不做任何有用工作的情况下,根据其他进程的变化不断改变其状态:

饥饿:调度程序无限期忽略可运行进程的情况;尽管它能够继续,但它从未被选中

假设三个进程(P1,P2,P3)都需要周期性地访问资源R。考虑P1拥有资源的情况,P2和P3都被延迟,等待该资源。当P1退出其临界段时,P2或P3应被允许访问R。假设操作系统授予P3访问权限,并且P1在P3完成其临界段之前再次需要访问权限。如果操作系统在P3完成后授予P1访问权,并且随后交替授予P1和P3访问权,则P2可能会无限期地拒绝对资源的访问,即使不存在死锁情况

附录A-并发主题

死锁示例

/* PROCESS 0 */
flag[0] = true;          // <- get lock 0
while (flag[1]){         
    flag[0] = false;     // <- instead of sleeping, we do useless work
                         //    needed by the lock mechanism
    /*delay */;          // <- wait for a second
    flag[0] = true;      // <- and restart useless work again.
}
/*critical section*/;    // <- do what we need (this will never happen)
flag[0] = false; 

/* PROCESS 1 */
flag[1] = true;
while (flag[0]) {
    flag[1] = false;
    /*delay */;
    flag[1] = true;
}
/* critical section*/;
flag[1] = false;
如果两个进程在其中一个执行while语句之前都将其标志设置为true,那么每个进程都会认为另一个已进入其关键部分,从而导致死锁

/* PROCESS 0 */
flag[0] = true;            // <- get lock 0
while (flag[1])            // <- is lock 1 free?
    /* do nothing */;      // <- no? so I wait 1 second, for example
                           // and test again.
                           // on more sophisticated setups we can ask
                           // to be woken when lock 1 is freed
/* critical section*/;     // <- do what we need (this will never happen)
flag[0] = false;           // <- releasing our lock

 /* PROCESS 1 */
flag[1] = true;
while (flag[0])
    /* do nothing */;
/* critical section*/;
flag[1] = false;
beginLock()
的成本远远高于
doSomething()
时,问题开始出现。非常夸张地说,想象一下当
beginLock
花费1秒,而
doSomething
只花费1毫秒时会发生什么

在这种情况下,如果您等待1毫秒,您将避免1秒钟受到阻碍

为什么
beginLock
会花这么多钱?如果锁是免费的,则不会花费很多(请参阅),但是如果锁不是免费的,则操作系统将“冻结”您的线程,设置一种机制在锁被释放时唤醒您,然后在将来再次唤醒您

所有这些都比一些检查锁的循环要昂贵得多。这就是为什么有时候做“旋转锁”更好的原因

例如:

void beginSpinLock(lock)
{
   if(lock) loopFor(1 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   if(lock) loopFor(2 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   // important is that the part above never 
   // cause the thread to sleep.
   // It is "burning" the time slice of this thread.
   // Hopefully for good.

   // some implementations fallback to OS lock mechanism
   // after a few tries
   if(lock) return beginLock(lock);
   else 
   {
     lock = true;
     return;
   }
}
如果你的工具
void beginSpinLock(lock)
{
   if(lock) loopFor(1 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   if(lock) loopFor(2 milliseconds);
   else 
   {
     lock = true;
     return;
   }

   // important is that the part above never 
   // cause the thread to sleep.
   // It is "burning" the time slice of this thread.
   // Hopefully for good.

   // some implementations fallback to OS lock mechanism
   // after a few tries
   if(lock) return beginLock(lock);
   else 
   {
     lock = true;
     return;
   }
}
Thread A : waits for lock 1
Thread B : waits for lock 2
Thread A : holds lock 1
Thread B : holds lock 2
Thread B : waits for lock 1
Thread A : waits for lock 2
Thread B : holds lock 2
Thread A : holds lock 1
Thread A : waits for lock 2
Thread B : waits for lock 1
Thread B : waits for lock 1
Thread A : waits for lock 2
Thread A : waits for lock 2
Thread B : waits for lock 1
Thread B : waits for lock 1
Thread A : waits for lock 2
Thread A : waits for lock 2
Thread B : waits for lock 1
...
static boolean commonVar = false;
Object lock = new Object;

...

void threadAMethod(){
    ...
    while(commonVar == false){
         synchornized(lock){
              ...
              commonVar = true
         }
    }
}

void threadBMethod(){
    ...
    while(commonVar == true){
         synchornized(lock){
              ...
              commonVar = false
         }
    }
}