Does the `in_inner ()` call on atoms cause all weakened records?

Does it return into_inner()all laidback entries in this sample program? If so, which concept guarantees this?

extern crate crossbeam;

use std::sync::atomic::{AtomicUsize, Ordering};

fn main() {
    let thread_count = 10;
    let increments_per_thread = 100000;
    let i = AtomicUsize::new(0);

    crossbeam::scope(|scope| {
        for _ in 0..thread_count {
            scope.spawn(|| {
                for _ in 0..increments_per_thread {
                    i.fetch_add(1, Ordering::Relaxed);
                }
            });
        }
    });

    println!(
        "Result of {}*{} increments: {}",
        thread_count,
        increments_per_thread,
        i.into_inner()
    );
}

( https://play.rust-lang.org/?gist=96f49f8eb31a6788b970cf20ec94f800&version=stable )

I understand that Crossbeam ensures that all threads are finished, and as ownership returns to the main thread, I also understand that there will be no outstanding borrowings, but as I see, there may still be outstanding pending records, if not on the processors, then in caches.

What concept ensures that all records are finished and all caches are synchronized back to the main thread when called into_inner()? Is it possible to lose records?

+4
3

into_inner() ? , ?

into_inner, , join.

into_inner - , (join , Arc try_unwrap ..), . , .

Crossbeam join :

[, ] , , .

:

, , into_inner()? ?

, Rust ++ . ++ 11 join. , join , , , join, .

join , .

+5

.

, , , . undefined, , into_inner. , into_inner crossbeam.

( ):

let thread_count = 10;
let increments_per_thread = 100000;
let i = Arc::new(AtomicUsize::new(0));
let threads: Vec<_> = (0..thread_count)
    .map(|_| {
        let i = i.clone();
        thread::spawn(move || for _ in 0..increments_per_thread {
            i.fetch_add(1, Ordering::Relaxed);
        })
    })
    .collect();

for t in threads {
    t.join().unwrap();
}

println!(
    "Result of {}*{} increments: {}",
    thread_count,
    increments_per_thread,
    i.load(Ordering::Relaxed)
);

! ? join . , , , , .

, , , , . Rust Nomicon, :

. - . , - . , , --, , . , , . , , fetch_add, .

- , . , , . , join , , . Rust , ++ 11 ( LLVM ), , ++ std:: thread:: join, " , *this, ". , ++ cppreference.com :

#include <vector>
#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> cnt = {0};

void f()
{
    for (int n = 0; n < 1000; ++n) {
        cnt.fetch_add(1, std::memory_order_relaxed);
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f);
    }
    for (auto& t : v) {
        t.join();
    }
    std::cout << "Final counter value is " << cnt << '\n';
}
+1

The fact that you can call into_inner(which consumes AtomicUsize) means that there is no more on this backup storage.

Each fetch_addis an atom with ordering Relaxed, therefore, as soon as the threads are completed, there should not be any changes that change it (if so, that is, there is an error in the crossbar).

Read more about the description into_innerfor more information.

0
source

Source: https://habr.com/ru/post/1687578/


All Articles