首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程:读取器/写入器锁,将读锁升级为写锁

线程:读取器/写入器锁,将读锁升级为写锁
EN

Stack Overflow用户
提问于 2010-03-09 08:28:42
回答 4查看 15.7K关注 0票数 16

我在Linux上使用读/写锁,并且我发现试图将读锁对象升级为写锁死锁。

代码语言:javascript
复制
// acquire the read lock in thread 1.
pthread_rwlock_rdlock( &lock );

// make a decision to upgrade the lock in threads 1.
pthread_rwlock_wrlock( &lock ); // this deadlocks as already hold read lock.

我读过手册页,它很具体。

调用线程如果在调用时持有读-写锁(无论是读锁还是写锁),则可能会死锁。

在这种情况下,将读锁升级为写锁的最佳方法是什么?我不想在我保护的变量上引入种族。

想必我可以创建另一个互斥锁,包括释放读锁和获取写锁,但我没有真正看到读/写锁的使用。我也可以简单地使用一个普通的互斥。

Thx

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-03-09 08:53:09

在下面的场景中,除了死锁之外,您还想要什么?

  • 线程1获取读锁
  • 线程2获取读锁
  • 线程1请求升级锁写入
  • 线程2请求升级锁写入

因此,我只需要释放读锁,获取写锁,然后再次检查是否需要进行更新。

票数 21
EN

Stack Overflow用户

发布于 2019-03-31 22:21:11

P线程库不直接支持此操作。

作为解决办法,您可以定义一个互斥锁来保护锁:

  • 来获取锁,首先获取互斥锁,然后是锁(根据需要读取或写入),然后释放互斥锁。
  • 来释放锁,只需释放它(这里不需要互斥)。
  • 升级锁,获取互斥锁,释放读锁,获得写锁,然后释放互斥锁。
  • 降低锁的级别,获取互斥锁,释放写锁,获得读锁,然后释放互斥锁。

这样,当您试图升级写锁时,没有其他线程可以抓取它。但是,当您试图升级时,如果其他线程持有读锁,则您的线程将阻塞。

此外,如前所述,如果两个线程同时试图升级同一锁,则会遇到死锁:

  • T1和T2都持有一个读锁。
  • T1希望升级,获取互斥锁,释放读锁并尝试获取写入锁。这被T2阻止。
  • T2希望升级,尝试获取互斥对象,并被T1.

阻止。

从我的CS讲座中吸取教训:死锁是无法可靠地避免的。对于提出的每个策略,至少有一个用例表明该策略是不切实际的。您唯一能做的就是检测死锁条件(即,如果调用在EDEADLK中失败),并确保您的代码已经准备好处理这种情况。(如何恢复在很大程度上取决于代码。)

以这种方式降级并不容易出现死锁,尽管降级和同时升级会导致死锁。如果只有一个线程以这种方式升级了该锁(如果需要,其他线程会立即获得写锁),也不会出现死锁。

正如其他人所说,当您可能需要时立即获得写锁,这将是一种不容易发生死锁的替代方法,但可能不必要地阻止其他读取操作同时进行。

结论:这取决于您的代码.

如果只读阶段很短(即足够短,以便您能够在那段时间内阻止其他读取操作),那么我将采用无偿的写锁方法。

如果只读阶段可能会持续很长时间,并且在此期间阻塞其他读取是不可接受的,那么进行互斥保护的锁升级,但是要么将其限制为每个锁一个线程(“只有T1可以升级锁L42,而不是其他线程”),或者提供一种检测死锁并从死锁中恢复的方法。

除非除此锁及其互斥项以外的其他资源发挥作用

票数 3
EN

Stack Overflow用户

发布于 2010-03-09 08:46:54

最简单和最安全的方法是从您想要更改数据的那一刻起就使用写锁,而不是从您确定要更改数据的那一刻开始。我知道这将使对数据的访问更加序列化。

当我读到这个问题时,我有点惊讶,因为我从来没有考虑过先读锁,然后升级到写锁。不同的情况可能需要不同的方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2407558

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档