1
+ <!--
1
2
# Data Races and Race Conditions
3
+ -->
2
4
5
+ # データ競合と競合状態
6
+
7
+ <!--
3
8
Safe Rust guarantees an absence of data races, which are defined as:
9
+ -->
10
+
11
+ 安全な Rust では、データ競合が存在しないことが保証されています。
12
+ データ競合は、以下のように定義されています。
4
13
14
+ <!--
5
15
* two or more threads concurrently accessing a location of memory
6
16
* one of them is a write
7
17
* one of them is unsynchronized
18
+ -->
8
19
20
+ * 2 つ以上のスレッドが並行にメモリ上の場所にアクセスしている
21
+ * この内 1 つは書き込み
22
+ * この内 1 つは非同期
23
+
24
+ <!--
9
25
A data race has Undefined Behavior, and is therefore impossible to perform
10
26
in Safe Rust. Data races are *mostly* prevented through rust's ownership system:
11
27
it's impossible to alias a mutable reference, so it's impossible to perform a
12
28
data race. Interior mutability makes this more complicated, which is largely why
13
29
we have the Send and Sync traits (see below).
30
+ -->
31
+
32
+ データ競合は未定義動作を含み、そしてそれ故に安全な Rust で発生させることは不可能です。
33
+ データ競合は Rust の所有権システムによって* ほとんど* 防がれています。可変参照の
34
+ エイリアスを生成することは不可能ですから、データ競合を起こすことは不可能です。
35
+ 内部可変性はこれをもっと複雑にします。これが、 Send トレイトと Sync トレイトが
36
+ 何故存在するかということの主な理由です (以下を見てください) 。
14
37
38
+ <!--
15
39
**However Rust does not prevent general race conditions.**
40
+ -->
16
41
42
+ ** しかしながら Rust は、一般的な競合状態を防ぎません。**
43
+
44
+ <!--
17
45
This is pretty fundamentally impossible, and probably honestly undesirable. Your
18
46
hardware is racy, your OS is racy, the other programs on your computer are racy,
19
47
and the world this all runs in is racy. Any system that could genuinely claim to
20
48
prevent *all* race conditions would be pretty awful to use, if not just
21
49
incorrect.
50
+ -->
51
+
52
+ これは根本的に不可能で、そして多分本当に望まれていないものです。ハードウェアは
53
+ 競合状態を起こし、 OS も競合状態を起こし、コンピュータの他のプログラムも競合状態を起こし、
54
+ そして世界中にある全てのプログラムも競合状態を起こします。どんなシステムでも、
55
+ * 全ての* 競合状態を防げると喧伝しているようなものは、単に間違っているだけではなく、
56
+ 本当に使いづらいものとなるでしょう。
22
57
58
+ <!--
23
59
So it's perfectly "fine" for a Safe Rust program to get deadlocked or do
24
60
something nonsensical with incorrect synchronization. Obviously such a program
25
61
isn't very good, but Rust can only hold your hand so far. Still, a race
26
62
condition can't violate memory safety in a Rust program on its own. Only in
27
63
conjunction with some other unsafe code can a race condition actually violate
28
64
memory safety. For instance:
65
+ -->
66
+
67
+ ですから、安全な Rust のプログラムがデッドロックに陥ったり、正しくない同期によって何か
68
+ 馬鹿げたことを行なっても、これは全く "問題ない" のです。明らかにそのようなプログラムは、
69
+ 本当に良くないです。ですが、 Rust は今までのところ、プログラマに我慢してもらうしか出来ないのです。
70
+ それでも Rust のプログラムだけでは、競合状態において、メモリ安全性を侵害することは出来ません。
71
+ 何か他のアンセーフなコードと組み合わせることだけでしか、実際に競合状態において、
72
+ メモリ安全性を侵害することが出来ないのです。例:
29
73
30
74
``` rust,no_run
31
75
use std::thread;
32
76
use std::sync::atomic::{AtomicUsize, Ordering};
33
77
use std::sync::Arc;
34
78
35
79
let data = vec![1, 2, 3, 4];
36
- // Arc so that the memory the AtomicUsize is stored in still exists for
37
- // the other thread to increment, even if we completely finish executing
38
- // before it. Rust won't compile the program without it, because of the
39
- // lifetime requirements of thread::spawn !
80
+ // Arc にすることで、 他のスレッドより前に完全に実行が終了しても、 AtomicUsize が
81
+ // 保存されているメモリが、他のスレッドがインクリメントするために存在し続けます。
82
+ // これ無しにはコンパイルできません。なぜなら、 thread::spawn が
83
+ // ライフタイムを必要とするからです !
40
84
let idx = Arc::new(AtomicUsize::new(0));
41
85
let other_idx = idx.clone();
42
86
43
- // `move` captures other_idx by-value, moving it into this thread
87
+ // `move` によって other_idx が値でキャプチャされ、このスレッドにムーブされます
44
88
thread::spawn(move || {
45
- // It's ok to mutate idx because this value
46
- // is an atomic, so it can't cause a Data Race.
89
+ // idx を変更しても大丈夫です。この値はアトミックだからです。
90
+ // ですからデータ競合は起こりません。
47
91
other_idx.fetch_add(10, Ordering::SeqCst);
48
92
});
49
93
50
- // Index with the value loaded from the atomic. This is safe because we
51
- // read the atomic memory only once, and then pass a copy of that value
52
- // to the Vec's indexing implementation. This indexing will be correctly
53
- // bounds checked, and there's no chance of the value getting changed
54
- // in the middle. However our program may panic if the thread we spawned
55
- // managed to increment before this ran. A race condition because correct
56
- // program execution (panicking is rarely correct) depends on order of
57
- // thread execution.
94
+ // アトミックなものからロードした値を使用してインデックス指定をします。これは安全です。
95
+ // なぜなら、アトミックメモリから読み込み、その値のコピーを Vec のインデックス実装に
96
+ // 渡すからです。このインデックス指定では、正しく境界チェックが行なわれ、そして途中で
97
+ // 値が変わることはありません。しかし、もしスポーンされたスレッドが、なんとかして実行前に
98
+ // インクリメントするならば、このプログラムはパニックするかもしれません。
99
+ // 正しいプログラムの実行 (パニックすることはほとんど正しくありません) は、スレッドの
100
+ // 実行順序に依存するため、競合状態となります。
58
101
println!("{}", data[idx.load(Ordering::SeqCst)]);
59
102
```
60
103
@@ -68,18 +111,18 @@ let data = vec![1, 2, 3, 4];
68
111
let idx = Arc::new(AtomicUsize::new(0));
69
112
let other_idx = idx.clone();
70
113
71
- // `move` captures other_idx by-value, moving it into this thread
114
+ // `move` によって other_idx が値でキャプチャされ、このスレッドにムーブされます
72
115
thread::spawn(move || {
73
- // It's ok to mutate idx because this value
74
- // is an atomic, so it can't cause a Data Race.
116
+ // idx を変更しても大丈夫です。この値はアトミックだからです。
117
+ // ですからデータ競合起こりません。
75
118
other_idx.fetch_add(10, Ordering::SeqCst);
76
119
});
77
120
78
121
if idx.load(Ordering::SeqCst) < data.len() {
79
122
unsafe {
80
- // Incorrectly loading the idx after we did the bounds check.
81
- // It could have changed. This is a race condition, *and dangerous*
82
- // because we decided to do `get_unchecked`, which is `unsafe`.
123
+ // 境界チェックを行なった後、間違えて idx をロードしてしまいます。
124
+ // この値は変わってしまったかもしれません。これは競合状態で、*危険*です。
125
+ // なぜなら `unsafe` である `get_unchecked` を行なったからです。
83
126
println!("{}", data.get_unchecked(idx.load(Ordering::SeqCst)));
84
127
}
85
128
}
0 commit comments