死锁和livelock有什么区别?

有人可以请示例(代码)解释死锁livelock之间的区别是什么?

取自http://en.wikipedia.org/wiki/Deadlock

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

活锁类似于死锁,除了活锁涉及的进程的状态不断地相互改变,没有任何进展。 活锁是资源匮乏的特例; 一般的定义只是说明一个具体的过程没有进展。

当两个人在狭窄的走廊里相遇时,一个真实世界的活锁的例子就是:两个人在一个狭窄的走廊里面相遇,每个人都试图通过移到旁边让对方通过而变得彬彬有礼,但是他们最终在没有取得任何进展的情况下左右摆动,同样的方式。

一些algorithm检测并从死锁中恢复时,活锁是一种风险。 如果多个进程采取行动,那么可以重复触发死锁检测algorithm。 这可以通过确保只有一个过程(随机select或优先select)采取行动来避免。

活锁

一个线程往往会响应另一个线程的动作。 如果另一个线程的行为也是对另一个线程的行为的响应,则可能导致活锁。

与死锁一样,活锁的线程也无法取得进一步的进展 。 但是, 线程并没有被阻塞 – 他们只是忙于响应对方恢复工作 。 这相当于两个人试图在走廊上通过对方:阿尔方塞向左移动让加斯顿通过,而加斯东向右移动让阿方斯通过。 看到他们还在互相阻拦,阿尔方斯走到他的右边,而加斯东向左走。 他们仍然互相阻拦,等等…

活锁死锁之间的主要区别是线程不会被阻塞,而是会不断尝试相互响应。

在这个图像中,两个圆(线程或进程)将尝试通过向左和向右移动给另一个空间。 但他们不能再进一步。

在这里输入图像说明

这里的所有内容和例子都是从

操作系统:内部和devise原则
William Stallings
8º版

僵局 :两个或两个以上的进程无法进行的情况,因为每个进程都在等待另一个进程做某事。

例如,考虑两个进程P1和P2以及两个资源R1和R2。 假设每个进程都需要访问这两个资源来执行其部分function。 那么可能会出现以下情况:OS将R1分配给P2,将R2分配给P1。 每个进程都在等待两个资源中的一个。 直到获得其他资源并执行需要这两个资源的function,才释放它已经拥有的资源。 这两个进程僵持不下

活锁(Livelock) :两个或更多进程不断响应其他进程的变化而不进行任何有用的工作而改变其状态的情况:

饥饿 :调度程序无限期地忽略可运行进程的情况; 虽然能够继续下去,但决不会被选中。

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

附录A – 合并的主题

死锁例子

如果两个进程在执行while语句之前将它们的标志设置为true,那么每个进程都会认为另一个进入了临界区,导致死锁。

/* PROCESS 0 */ flag[0] = true; while (flag[1]) /* do nothing */; /* critical section*/; flag[0] = false; /* PROCESS 1 */ flag[1] = true; while (flag[0]) /* do nothing */; /* critical section*/; flag[1] = false; 

活锁示例

 /* PROCESS 0 */ flag[0] = true; while (flag[1]){ flag[0] = false; /*delay */; flag[0] = true; } /*critical section*/; flag[0] = false; /* PROCESS 1 */ flag[1] = true; while (flag[0]) { flag[1] = false; /*delay */; flag[1] = true; } /* critical section*/; flag[1] = false; 

考虑以下一系列事件:

  • P0将flag [0]设置为true。
  • P1将flag [1]设置为true。
  • P0检查标志[1]。
  • P1检查标志[0]。
  • P0将flag [0]设置为false。
  • P1将flag [1]设置为false。
  • P0将flag [0]设置为true。
  • P1将flag [1]设置为true。

这个顺序可以无限延长,任何一个进程都不能进入其关键部分。 严格地说,这不是死锁 ,因为两个进程的相对速度的任何改变都会打破这个循环,并允许一个进入临界区。 这种情况被称为活锁 。 回想一下当一组进程希望进入其关键部分但是没有进程能够成功时发生死锁。 有了活锁 ,就有可能成功的执行顺序,但也可以描述一个或多个执行顺序,其中没有任何进程进入其关键部分。

DEADLOCK死锁是任务等待不能满足条件的一个条件 – 任务要求对共享资源进行独占控制 – 任务在等待其他资源被释放时保存资源 – 任务不能被强制重新调用资源 – 循环等待条件存在

LIVELOCK当两个或两个以上的任务依赖并使用某些资源导致循环依赖条件(这些任务永远持续运行),从而阻止所有较低优先级的任务运行(这些较低优先级的任务遇到一个称为“饥饿”的条件)时,

也许这两个例子说明了死锁和livelock之间的区别:


Java的例子的死锁:

 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class DeadlockSample { private static final Lock lock1 = new ReentrantLock(true); private static final Lock lock2 = new ReentrantLock(true); public static void main(String[] args) { Thread threadA = new Thread(DeadlockSample::doA,"Thread A"); Thread threadB = new Thread(DeadlockSample::doB,"Thread B"); threadA.start(); threadB.start(); } public static void doA() { System.out.println(Thread.currentThread().getName() + " : waits for lock 1"); lock1.lock(); System.out.println(Thread.currentThread().getName() + " : holds lock 1"); try { System.out.println(Thread.currentThread().getName() + " : waits for lock 2"); lock2.lock(); System.out.println(Thread.currentThread().getName() + " : holds lock 2"); try { System.out.println(Thread.currentThread().getName() + " : critical section of doA()"); } finally { lock2.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer"); } } finally { lock1.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer"); } } public static void doB() { System.out.println(Thread.currentThread().getName() + " : waits for lock 2"); lock2.lock(); System.out.println(Thread.currentThread().getName() + " : holds lock 2"); try { System.out.println(Thread.currentThread().getName() + " : waits for lock 1"); lock1.lock(); System.out.println(Thread.currentThread().getName() + " : holds lock 1"); try { System.out.println(Thread.currentThread().getName() + " : critical section of doB()"); } finally { lock1.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer"); } } finally { lock2.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer"); } } } 

示例输出:

 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 

Java-livelock的例子:

 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LivelockSample { private static final Lock lock1 = new ReentrantLock(true); private static final Lock lock2 = new ReentrantLock(true); public static void main(String[] args) { Thread threadA = new Thread(LivelockSample::doA, "Thread A"); Thread threadB = new Thread(LivelockSample::doB, "Thread B"); threadA.start(); threadB.start(); } public static void doA() { try { while (!lock1.tryLock()) { System.out.println(Thread.currentThread().getName() + " : waits for lock 1"); Thread.sleep(100); } System.out.println(Thread.currentThread().getName() + " : holds lock 1"); try { while (!lock2.tryLock()) { System.out.println(Thread.currentThread().getName() + " : waits for lock 2"); Thread.sleep(100); } System.out.println(Thread.currentThread().getName() + " : holds lock 2"); try { System.out.println(Thread.currentThread().getName() + " : critical section of doA()"); } finally { lock2.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer"); } } finally { lock1.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer"); } } catch (InterruptedException e) { // can be ignored here for this sample } } public static void doB() { try { while (!lock2.tryLock()) { System.out.println(Thread.currentThread().getName() + " : waits for lock 2"); Thread.sleep(100); } System.out.println(Thread.currentThread().getName() + " : holds lock 2"); try { while (!lock1.tryLock()) { System.out.println(Thread.currentThread().getName() + " : waits for lock 1"); Thread.sleep(100); } System.out.println(Thread.currentThread().getName() + " : holds lock 1"); try { System.out.println(Thread.currentThread().getName() + " : critical section of doB()"); } finally { lock1.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 1 any longer"); } } finally { lock2.unlock(); System.out.println(Thread.currentThread().getName() + " : does not hold lock 2 any longer"); } } catch (InterruptedException e) { // can be ignored here for this sample } } } 

示例输出:

 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 ... 

这两个例子强制线程以不同的顺序获得锁。 当死锁等待另一个锁时,活锁并不真正等待 – 它拼命试图获取锁而没有获得锁。 每一次尝试都会消耗CPU周期。

参考: http : //operatingsystemgeeks.blogspot.in/死锁例子:互斥条件适用,因为一次只有一辆车可以在街道上。 保持等待条件适用,因为每辆车都占据了街道的一部分,并等待移动到街道的下一段。 无先占条件适用,因为被车辆占用的街道的一部分街道不能被带走。 循环等待条件适用,因为每辆车正在等待下一辆车移动。 也就是说,交通中的每辆车正在等待下一辆车在交通中所占的一段街道。