这些代码使用 Rust Dashmap 会产生死锁吗?

Posted

技术标签:

【中文标题】这些代码使用 Rust Dashmap 会产生死锁吗?【英文标题】:Will these code produce a deadlock using Rust Dashmap? 【发布时间】:2022-01-14 21:00:30 【问题描述】:

这样的代码会在 Rust 中使用 DashMap 产生死锁吗?

// snippet_1
let a = DashMap::new();
let b = DashMap::new();

// thread1
for v in a.iter()
   xxx

for v in b.iter()
   xxx


//thread2
for v in b.iter()
   xxx

for v in a.iter()
   xxx

// snippet_2
let a = DashMap::new();
let b = DashMap::new();

// thread1
for v in a.iter()
   xxx

for v in b.iter()
   xxx


//thread2
for v in b.iter()
   xxx
   for v in a.iter() 
      xxx
   
   xxx

// snippet_3
let a = DashMap::new();
let b = DashMap::new();

// thread1
for v in a.iter()
   xxx

for v in b.iter()
   xxx


//thread2
for v in b.iter()
   xxx
   let Some(v) = a.get_mut(key)
      xxx
   
   xxx

此外,在同一个线程中迭代时插入到 dashmap 会产生死锁。但是,从另一个线程插入 dashmap 不会产生死锁。这是真的吗?

【问题讨论】:

【参考方案1】:

这些示例都不会产生死锁。

来自文档:

insert():在映射中插入一个键和一个值。如果有一个键,则返回与键关联的旧值。 锁定行为:如果在地图中持有任何类型的引用时调用,可能会死锁。

iter():在 DashMap 上创建一个迭代器,产生不可变引用。锁定行为:如果在将可变引用保存到映射中时调用可能会死锁。

get_mut():获取对映射中条目的可变引用锁定行为:如果在对映射中持有任何类型的引用时调用,可能会死锁。

说明:

在您的前两个示例中,仅使用了iter(),因此只要不使用其他将可变引用引入映射的操作,就不会出现死锁。

在您的第三个示例中,DashMap b 仅再次与 iter() 一起使用,因此那里没有死锁。对于 DashMap a,有两种可能的执行流程:

    如果线程1首先到达a.iter(),那么线程2将不得不在a.get_mut(key)等待,但是一旦线程1完成了对a的迭代,线程2将能够继续,因此不会出现死锁。 如果线程 2 先到达a.get_mut(key),那么线程 1 将不得不在a.iter() 等待,但一旦线程 2 完成,它就可以继续,不会出现死锁。

其他问题

在同一线程中迭代时插入 DashMap 会产生死锁。

示例

for v in a.iter()  // This takes a reference into `a`
    a.insert(...) // Will deadlock because you hold a reference into `a`

从一个线程插入 DashMap 并在另一个线程中对其进行迭代不会产生死锁,其中一个只会等待另一个。

示例

//thread1
for v in a.iter() //If thread2 reaches `insert()` first, this will wait until it has finished.
    xxx


//thread2
for i in 1..1000 
    a.insert(i, i); // If thread1 reaches `iter()` first, this will wait until it has finished.

需要注意的是,在最后一个示例和问题的第三个示例中,insert()iter() 在开始之前可能不会等待整个循环完成,而是两个循环的执行将是交错,但它们永远不会在完全相同的时间执行。

【讨论】:

"相反,两个循环的执行是交错的",你的意思是在thread1中,每个for循环都会持有和释放锁,并且在间隔中,thread2可以在@987654337中插入一些值@,然后thread1可能会迭代刚刚插入的值? 我的意思是,在最后一个示例中,thread1 和 thread2 可以交替持有锁并在将锁传递给另一个线程之前执行不同数量的迭代,而不是任何一个线程在其他有机会跑。是的,这意味着 thread2 可以在 map 中插入一些东西,然后 thread1 可以读取它。

以上是关于这些代码使用 Rust Dashmap 会产生死锁吗?的主要内容,如果未能解决你的问题,请参考以下文章

Rust入坑指南:齐头并进(下)

死锁产生的条件以及解决方法

为啥在全局范围内声明通道会产生死锁问题

Java中线程死锁问题

死锁产生的条件及其预防

死锁产生的条件及其预防