Skip to content

Using Release in the store operation for make_mut just prevent out-of-thin-air value? #133284

Open
@xmh0511

Description

@xmh0511

In https://doc.rust-lang.org/src/alloc/sync.rs.html#2267, the make_mut is implemented as

if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err(){
  // ...
}else if this.inner().weak.load(Relaxed) != 1 {  // #0
 //...
}else{
  this.inner().strong.store(1, Release);  // #1
}

while upgrade is

if self.inner()?.strong.fetch_update(Acquire, Relaxed, checked_increment).is_ok(){
   Some(...)
}else{
 None
}

The Release at #1 concerns this case

// thread 1:
let mut_ref = Arc::make_mut(&mut my_arc);
*mut_ref = 10;

//thread 2: 
let arc = weak.upgrade().unwrap();
drop(weak);
println!("{}", *arc);

In this case, upgrade will return Some if it reads #1 and #1 is executed only #0 reads the value written by weak.fetch_sub(1, Release) in drop(weak);, so the model can be simplified as

weak = 2;
strong = 0;
// thread 1:
if weak.load(Relaxed) == 1{  // #1
   strong.store(1, Relaxed) // if the Release is changed to Relaxed  // #2
}
// thread 2:
while strong.load(Relaxed) !=0{ // #3
}
weak.store(1, Relaxed); // #4

#1 read #4, #4 is executed only if #3 read #2, #2 is executed only if #1 read #4. It depends on the out-of-thin-air value. Do we need a release memory order here to prevent OOTD?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-atomicArea: Atomics, barriers, and sync primitivesC-discussionCategory: Discussion or questions that doesn't represent real issues.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions