1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! This module contains all the core primitives the thread aware system is built upon.
use crateAffinity;
/// Marks types that correctly handle isolation when transferred between threads.
///
/// For performance reasons mentioned in the [crate documentation](`crate`), the basic
/// goal of the `ThreadAware` trait is that after calling [`ThreadAware::relocate()`],
/// the value should be as independent as possible from any state on the source
/// (or any other) thread in the sense that interacting with the object should not result
/// in contention over synchronization primitives when this interaction happens in parallel
/// with interactions with related values (e.g. clones) on other threads.
///
/// What this means depends on the type, but there are a couple of common implementation
/// strategies:
///
/// * No-op - this implies that the value doesn't have any dependency on other values
/// that may result in synchronization primitive contention, so it can be transferred as is. This
/// approach can be also be achieved by wrapping a value in the
/// [`Unaware`](`crate::Unaware`) type.
/// * Construct a per-affinity value - with this approach, each affinity gets its own
/// independently-initialized value. The [`Arc::new_with`](`crate::Arc::new_with`)
/// function facilitates this approach.
/// * Utilize true sharing in a controlled manner - have some data that is actually shared
/// between the values on different affinities, but in a controlled manner that minimizes
/// the contention for the synchronization primitives necessary. This is a more advanced
/// technique allowing for designs that minimize contention while avoiding wasting resources
/// by duplicating them for each affinity.
///
/// As an example, let's implement a counter that counts per-affinity. This counter will use
/// interior mutability to to allow increments with just a shared reference, but we want to
/// avoid contention on the internal state, so each affinity will get an independent counter.
///
/// ```rust
/// # use std::sync::atomic::{AtomicI32, Ordering};
/// # use std::sync::Arc;
/// # use thread_aware::{ThreadAware};
/// # use thread_aware::affinity::*;
/// #[derive(Clone)]
/// struct Counter {
/// value: Arc<AtomicI32>,
/// }
///
/// impl Counter {
/// fn new() -> Self {
/// Self {
/// value: Arc::new(AtomicI32::new(0)),
/// }
/// }
///
/// fn increment_by(&self, value: i32) {
/// self.value.fetch_add(value, Ordering::AcqRel);
/// }
///
/// fn value(&self) -> i32 {
/// self.value.load(Ordering::Acquire)
/// }
/// }
///
/// impl ThreadAware for Counter {
/// fn relocate(&mut self, _source: Option<Affinity>, _destination: Affinity) {
/// // Initialize a new value in the destination affinity independent
/// // of the source affinity.
/// self.value = Arc::new(AtomicI32::new(0));
/// }
/// }
/// ```
///
/// Note that this trait requires [`Send`] because relocation inherently moves data across threads.