死锁和活锁有什么区别?

mac*_*ows 313 multithreading deadlock pthreads livelock

有人可以解释一下(代码)的例子,死锁活锁之间的区别是什么?

mah*_*mah 372

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

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

活锁类似于死锁,不同之处在于所涉及的活锁的过程的状态不断地相对于彼此改变,没有取得进展.活锁是资源匮乏的特例; 一般定义仅表明特定过程没有进展.

当两个人在狭窄的走廊中相遇时,会发生一个真实的活锁示例,每个人都试图通过移动到另一个通过来礼貌,但他们最终会左右摇摆而没有任何进展,因为他们都反复移动以同样的方式同时进行.

Livelock是一种风险,有些算法可以检测并从死锁中恢复.如果多个进程采取行动,则可以重复触发死锁检测算法.通过确保只有一个进程(随机选择或按优先级)采取行动,可以避免这种情况.

  • 我不会提供代码示例,但请考虑两个进程,每个进程等待另一个进程的资源,但是以非阻塞方式等待.当每个人都知道他们无法继续他们释放他们的资源并且睡眠30秒时,他们会检索他们的原始资源,然后尝试其他进程所持有的资源,然后离开,然后再获得.由于这两个过程都试图应对(只是很糟糕),这是一个活锁. (59认同)
  • 死锁示例更容易......假设有两个进程A和B,并且每个进程都需要资源r1和资源r2.假设A接收(或已经拥有)r1,并且B接收(或已经拥有)r2.现在每个人都试图获得对方拥有的资源,没有任何超时.A被阻止,因为B保持r2,并且B被阻止,因为A保持r1.每个进程都被阻塞,因此无法释放对方想要的资源,从而导致死锁. (29认同)
  • 我已经找到了,但他们没有你可以看到的例子,谢谢,无论如何 (8认同)
  • 你能给我相同的例子,但有僵局,提前谢谢 (4认同)
  • 在Transactional内存的背景下,有一个很棒的视频演示死锁和活锁:http://www.youtube.com/watch?v = _IxsOEEzf-c (2认同)
  • 如果问题可以自行解决,我认为这并不是真正的活锁——只是一个低效的资源获取计划。 (2认同)

Bur*_*man 76

活锁

线程通常用于响应另一个线程的操作.如果另一个线程的操作也是对另一个线程的操作的响应,则可能导致活锁.

与死锁一样,活锁线程无法取得进一步进展.但是,线程没有被阻塞 - 他们只是太忙于相互回应以恢复工作.这相当于两个试图在走廊里互相通过的人:Alphonse向左移动让Gaston通过,而Gaston向右移动让Alphonse通过.看到他们仍在相互阻挡,Alphonse向右移动,而Gaston向左移动.他们还在互相阻挡,等等......

活锁死锁之间的主要区别在于线程不会被阻塞,而是会尝试连续响应彼此.

在此图像中,两个圆(线程或进程)将尝试通过向左和向右移动为另一个提供空间.但他们无法继续前进.

在此输入图像描述

  • 这东西有个名字。也许是一个俚语,但仍然是:[schlumperdink](https://www.urbandictionary.com/define.php?term=schlumperdink) :P (2认同)

Dan*_*ite 59

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

操作系统:与设计原理
威廉·斯托林斯
8º版

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

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

Livelock:一种情况,其中两个或多个进程连续更改其状态以响应其他进程的更改而不执行任何有用的工作:

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

假设三个进程(P1,P2,P3)都需要定期访问资源R.考虑P1拥有资源的情况,P2和P3都被延迟,等待该资源.当P1退出其临界区时,应允许P2或P3访问R.假设操作系统授予对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;
Run Code Online (Sandbox Code Playgroud)

活锁示例

/* 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;
Run Code Online (Sandbox Code Playgroud)

[...]考虑以下事件序列:

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

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


Dee*_*ane 13

DEADLOCK 死锁是一种条件,在这种情况下,任务无限期地等待永远不能满足的条件 - 任务声明对共享资源的独占控制 - 任务在等待释放其他资源时保留资源 - 不能强制任务重新启动资源 - 循环等待条件存在

LIVELOCK 当两个或多个任务依赖并使用某个资源导致循环依赖条件,其中这些任务继续永久运行时,可能会出现Livelock条件,从而阻止所有较低优先级的任务运行(这些较低优先级的任务会遇到称为饥饿的情况)


mmi*_*ldt 7

也许这两个示例向您说明了死锁和活锁之间的区别:


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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

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
Run Code Online (Sandbox Code Playgroud)

活锁的Java示例:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

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
...
Run Code Online (Sandbox Code Playgroud)

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