如果锁保证原子性,该如何发生僵局

发布于 2025-01-31 12:19:46 字数 750 浏览 4 评论 0原文

情况1:

//snippet1
a=1
if(a!=0){
print(a);
}
//snippet2
a=0;

假设Thread T1正在执行Snippet1,检查IF条件(为true),进入IF的范围,然后中断T1,而T2执行Snippet2,现在T1恢复并执行打印(A)。这是错误的,即使A现在为0,T1仍在继续并打印,尽管条件是错误的。 我阅读的上述问题的解决方案是在Snippet1上获得锁,然后直到Snippet1结束,T1才会被中断。

足够!

但是我对以下情况有疑问: 情况2:

//snippet3
acquire_lock1;
{
acquire_lock2;
}

//snippet4
acquire_lock2;
{
acquire_lock1;
}

假设线程T3正在执行Snippet3和T4执行STIPPET4。假设T3收购了Lock1,被打断了,T4收购了Lock2并继续获取Lock1,但现在由T3持有。因此,这是僵局的经典例子。

我在理解的是,如果获取锁定保证的执行原子性,并且一旦在关键部分中获取锁定,我们就无法中断该线程,那么在获取lock1之后,如何中断了t3,而T4则继续执行。 。 据我说,一旦Lock1被T3获取,它应该开始执行而不会中断,获取Lock2,Release loce2,Release Lost1,并完成整个过程而不会中断。但是,这种方式将永远不会发生僵局。

谁能向我解释这个思考过程怎么了,什么时候可以发生僵局?

提前致谢!

Situation 1:

//snippet1
a=1
if(a!=0){
print(a);
}
//snippet2
a=0;

lets say thread T1 is executing snippet1, checks the if condition (which is true),enters the scope of if, then T1 is interrupted, and T2 executes snippet2, now T1 resumes and executes print(a). this is wrong as even though a is now 0, T1 goes ahead and prints despite the if condition being false.
The solution to the above problem that I read is acquire a lock on snippet1, then until the snippet1 is over, T1 won't be interrupted.

Good enough!

But I have a doubt regarding the following:
Situation 2:

//snippet3
acquire_lock1;
{
acquire_lock2;
}

//snippet4
acquire_lock2;
{
acquire_lock1;
}

Lets say thread T3 is executing snippet3 and T4 executing snippet4. Say T3 acquired lock1, was interrupted, T4 acquired lock2 and went on to acquire lock1, but it is now held by T3. So now this is a classic example of deadlock.

I am having problem in understanding that, if acquiring a lock guarantees atomicity of execution, and that once lock is acquired on the critical section, we cannot interrupt that thread, then how come after acquiring lock1 was T3 interrupted and T4 went on with the execution.
According to me, once lock1 is acquired by T3, it should begin execution without getting interrupted ,acquire Lock2, release lock2,release lock1, and complete this entire process without interruption. But this way a deadlock shall never occur.

Can anyone explain me whats wrong with this thought process, and when exactly can a deadlock occur?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

睡美人的小仙女 2025-02-07 12:19:46

正如@kayaman在那里所说的那样:“获取锁并不意味着该线程不会被打断”。

该锁只是保护(“警卫”)一个代码部分,以免同时由两个线程执行(或者其他线程可以在另一个线程留下之前输入该部分)。从技术上讲,获得的锁只能保证没有其他线程可以同时获得相同的锁。这意味着此类线程在获取语句中等待,直到发布锁(或超时到期,或者地狱冻结…… - 为了进行以下讨论,不需要这些详细信息)。

因此,当Thread1在第1节开始时获取Lock1,然后在不返回锁定的情况下死亡时,没有其他线程可以输入第1节。或者在握住锁定时将中断线程1时,必须重新控制才能释放锁定,然后才能进入任何其他线程。

您的第二种情况现在容易发生死锁:

  1. Thread1在输入extifer1_1时获取lock1,该lock
  2. thread2获得了锁定2_1的pulte2_1,thread1,thread1,
  3. thread1前进到lock2守护的第1_2章的开始,
  4. thread2 the thready thready thread1 the thread1 lock lock lock2失败,因为这已经由Thread2
  5. thread1固定了,现在等待,同时释放了lock2
  6. ,同时thread2 thread2高于lock1守护的第2_2的开始,
  7. 因为lock1已经由thread1持有,thread1已经由thread2固定,thread2尝试获取锁定锁定失败
  8. 现在的thread2等待lock1 be lock1是 发布
  9. 由于两个线程都在相互等待另一个线程以释放线程时

,因此您的程序被困在僵局中一种简单的方法来防止这是确保始终以相同的序列将锁定(也称为“ ABC”)规则):当线程需要锁定lock_one,lock_two,lock_three时,他们必须始终按照其名称的顺序获取它们(第一个lock_one,然后是lock_three,最后,lock_two)。尽管这似乎是不合逻辑的(因为所选的名称……)保证您不会获得死锁。线程只有在已经获取lock_one的情况下才能获取lock_three,或者根本不需要lock_one;对于lock_two而言,

如果由于某种原因需要在lock_three之前获取lock_two…重命名锁,以便ABC规则将再次工作 - 然后调整您的代码!

As @Kayaman said already in there comment: "Acquiring a lock doesn't mean that the thread can't be interrupted".

The lock just protects ("guards") a code section from being executed by two threads at the same time (or that another thread may enter that section before another thread has left it). Technically, an acquired lock only guarantees that no other thread can acquire the same lock at the same time. This means that such another thread waits in the acquire statement until the lock is released (or a timeout expires, or hell freezes over … – for the following discussion, these details are not required).

So when Thread1 acquires Lock1 at the beginning of Section1, and then dies without returning the lock, no other thread may enter Section1. Or when Thread1 will be interrupted while holding the lock, it has to get back control to be able to release the lock before any other thread may enter Section1.

Your second scenario is now prone to a deadlock:

  1. Thread1 acquires Lock1 when entering Section1_1, guarded by this lock
  2. Thread2 acquires Lock2, guarding Section2_1,
  3. Thread1 advances to the begin of Section1_2 that is guarded by Lock2
  4. The attempt by Thread1 to acquire Lock2 fails, because this is already hold by Thread2
  5. Thread1 now waits that Lock2 is released
  6. Meanwhile Thread2 advanced to the begin of Section2_2 that is guarded by Lock1
  7. As Lock1 is already hold by Thread1, the attempt by Thread2 to acquire that lock fails
  8. Now Thread2 wait for Lock1 to be released
  9. As both threads are now mutually waiting for the other one to release the thread, your program is trapped in a deadlock

An easy way to prevent that is to ensure that locks are always taken in the same sequence (also known as the 'ABC' rule): when threads need the locks Lock_One, Lock_Two, Lock_Three, they have to acquire them always in the sequence of their names (first Lock_One, then Lock_Three, finally Lock_Two). Although this seems not logical (because of the chosen names …) it guarantees that you do not get a dead lock. A thread can acquire Lock_Three only if it has already acquired Lock_One, or it does not need Lock_One at all; same for Lock_Two …

If for some reason it is required to acquire Lock_Two before Lock_Three … rename the locks so that the ABC rule will work again – and adjust your code afterwards!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文