Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLOBAL_DEFINED_WORDS: 同期に関する操作の2項関係たちを追加 #1360

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions GLOBAL_DEFINED_WORDS.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,21 @@
"例外": {
"yomi": "れいがい",
"desc": "問題が発生したときに、現在実行位置を過去に通過・記録した位置に戻し、文脈情報を添えて紐づけられた処理(例外ハンドラー)を呼び出す仕組み。またはその事態"
},
"と同期する": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これだと と同期しない という活用のときにマークアップが適用されませんね…

やはり新しく単語を作るか "synchronize with 関係" みたいに英語を保持するか。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当該関数の仕様は "Synchronization: None" となっており、これを意訳したようです。
上記については書き換えてしまえば「同期しない」という否定系は避けられるとは思います。

Copy link
Member Author

@akinomyoga akinomyoga Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最終的に synchronizes with =「と同期する」で行くのか分かりませんが、取り敢えず f2ae0d6

「処理系(標準ライブラリ)に対する『他の操作と同期しなければならない』という要求はないが、処理系がやりたければ勝手に同期的に動作しても良い」という理解はあっていますか。元の表現だと「処理系は同期してはいけない」というのが規格の要件のようにも読めるので、こういう修正にしました。

Copy link
Member Author

@akinomyoga akinomyoga Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"A は B と同期する" という表現だと対称律が成立していそうでよくないなという気がして来ました (「『A は B と同期する』⇔『B は A と同期する』」と勘違いしそう)。例えば "に対して同期する" みたいな方向性のある表現の方が良いのでは。

Edit:

関連する懸念として "synchronizes with 関係" などの語を導入する場合にも、方向性を表現しにくいという問題がある気がします。"A と B は synchronizes with 関係にある" や "A は B と synchronizes with 関係にある" だとよくない。これも "A は B に対して synchronizes with 関係にある" などのようにすれば良いでしょうか。

あと "A は B に対して happens before 関係" や "A は B に対して synchronizes with 関係" などの表現は、"より前に発生する" や "に対して同期する" と比べると余り直感的でなく意味を捉えにくいかも、と思いました。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここで出てきている語の前提知識ほぼない状態で印象論でコメントしておくと、やはり「同期する」とか「関係にある」だと、交換法則が成り立つイメージがどうしてもある気がしています。Golangの訳はそれと比べてわかりやすい気がします。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akinomyoga

「処理系(標準ライブラリ)に対する『他の操作と同期しなければならない』という要求はないが、処理系がやりたければ勝手に同期的に動作しても良い」という理解はあっていますか。
元の表現だと「処理系は同期してはいけない」というのが規格の要件のようにも読めるので、こういう修正にしました。

うーん... 自信をもった回答ではありませんが、下記ニュアンスなのかなと思います。cpprefjpとしては B の意図が誤解なく伝われば十分ですから、修正後の文面 「特に他操作と同期する規定はない」 には賛同です。

  • A: 標準ライブラリ実装者向け:同期的な動作として実装することは否定されない。ただし、その必要性もないしパフォーマンス低下につながるため推奨しない。
  • B: 利用者(プログラマ)向け:API仕様として同期的な操作を期待してはいけない=スレッド間同期に使うな。

Copy link
Member

@yohhoy yohhoy Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akinomyoga : "A は B と同期する" という表現だと対称律が成立していそうでよくないなという気がして来ました (「『A は B と同期する』⇔『B は A と同期する』」と勘違いしそう)。

@yumetodo : やはり「同期する」とか「関係にある」だと、交換法則が成り立つイメージがどうしてもある気がしています。

お二人ともご指摘されるように、「A は B と同期する」では対称性あり/交換可能と誤解されるリスクはあると思います。ただこれは原語 A synchronizes with B 時点でも同じニュアンスを持つ気がしており、形式的定義の難解さによるものかなと半ばあきらめています...

挙げられている「A は B に対して同期する」は「~と同期する」よりも方向を持つニュアンスがある感じがするので、よい訳語かもしれませんね。

"yomi": "とどうきする",
"desc": "synchronizes with。「A は B と同期する」という記述は「A が B よりも前に発生する」関係を保証する"
},
"に対して同期する": {
"yomi": "にたいしてどうきする",
"desc": "synchronizes with。「A は B に対して同期する」という記述は「A が B よりも前に発生する」関係を保証する"
},
"よりも前に発生する": {
"yomi": "よりもまえにはっせいする",
"desc": "happens before。(異なるスレッド間の) 2つの操作の実行順序を規定する関係"
},
"よりも確実に前に発生する": {
"yomi": "よりもかくじつにまえにはっせいする",
"desc": "strongly happens before。(異なるスレッド間の) 2つの操作の実行順序を規定する強い関係"
}
}
6 changes: 3 additions & 3 deletions reference/atomic/memory_order.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace std {

## 概要
コンパイラに許可されている最適化の一つに、「プログラムの意味を変えない限りにおいて、メモリアクセスの順番を変えたり、省略したりしてもよい」というものがある。また、マルチコアCPUにおいては、あるCPUコアによるメモリアクセスの順序が他のコアからも同じように見えるとは限らない。このような挙動はマルチスレッドプログラミングにおいて問題になることがある。
この問題への対処として、C++11では各スレッドの実行に順序付けをするための"happens before"(先行発生)という関係を定義し、それによってあるスレッドでの操作が他スレッドから可視になるか否かを定めている。
この問題への対処として、C++11では各スレッドの実行に順序付けをするための「よりも前に発生する」という関係を定義し、それによってあるスレッドでの操作が他スレッドから可視になるか否かを定めている。
atomic変数においては、"release"操作によって書き込まれた値を"acquire"操作によって別のスレッドが読み出した場合に、そのrelease操作とacquire操作の間に順序付けが行われる。以下に例を挙げる。

```cpp example
Expand Down Expand Up @@ -65,8 +65,8 @@ int main()
3
```

[`atomic<bool>`](atomic.md)型の変数`ready`への読み書きに注目すると、`main()`では変数`ready`に `true` を"release"操作として書き込み、`f()`では"acquire"操作としての読み込みを `true` が返されるまで繰り返している。よって、`f()`の`while`ループを抜けた時点で、`main()`の`ready.store()`と`f()`の`ready.load()`の間に順序付け(happens before関係)が成立している。
ここでさらに変数`data`への読み書き(1), (2)に注目すると、(1)は`ready.store()`より前、(2)は`ready.load()`より後にあるので、以下のようなスレッド間の順序付け(happens before関係)が成立することになる。
[`atomic<bool>`](atomic.md)型の変数`ready`への読み書きに注目すると、`main()`では変数`ready`に `true` を"release"操作として書き込み、`f()`では"acquire"操作としての読み込みを `true` が返されるまで繰り返している。よって、`f()`の`while`ループを抜けた時点で、`main()`の`ready.store()`と`f()`の`ready.load()`の間に順序付け(「よりも前に発生する」関係)が成立している。
ここでさらに変数`data`への読み書き(1), (2)に注目すると、(1)は`ready.store()`より前、(2)は`ready.load()`より後にあるので、以下のようなスレッド間の順序付け(「よりも前に発生する」関係)が成立することになる。
(1) → `ready.store()` → `ready.load()` → (2)
よって、(1)における書き込みが(2)の時点で可視であることが保証される。
このようにしてC++のマルチスレッドプログラムにおける実行順序および可視性を理解することができる。
Expand Down
2 changes: 1 addition & 1 deletion reference/barrier/barrier.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace std {
- 完了関数を呼び出す。`completion()`と等価。
- フェーズ同期ポイント上でブロックされている全スレッドのブロックを解除する。

完了ステップの終了は、完了ステップによりブロック解除される全ての関数呼び出しからの復帰よりも、確実に前に発生(strongly happens before)する
完了ステップの終了は、完了ステップによりブロック解除される全ての関数呼び出しからの復帰**よりも確実に前に発生する**
テンプレートパラメータ`CompletionFunction`のデフォルト値以外の特殊化においては、完了ステップの進行中にバリアオブジェクトの[`wait()`](barrier/wait.md)を除くメンバ関数が呼び出されると、その動作は未定義となる。

テンプレートパラメータ`CompletionFunction`のデフォルト値は、追加で Cpp17DefaultConstructible 要件を満たす未規定の型であり、式`completion()`は何の副作用も生じない。
Expand Down
4 changes: 2 additions & 2 deletions reference/syncstream/basic_syncbuf/emit.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ bool emit();


## 同期操作
同じストリームバッファオブジェクトに文字を転送するすべての`emit()`呼び出しは、「happens before」関係と一致する全順序で実行されるように見える。各`emit()`呼び出しは、その全順序で後続の`emit()`呼び出しと同期する。実際には、これは下記の備考にあることを意味する。
同じストリームバッファオブジェクトに文字を転送するすべての`emit()`呼び出しは、「よりも前に発生する」関係と一致する全順序で実行されるように見える。各`emit()`呼び出しは、その全順序で後続の`emit()`呼び出し**に対して同期する**。実際には、これは下記の備考にあることを意味する。

注:ここでは、happens before 関係は全順序関係になっていると考えられる。また、modification order と矛盾しないとも考えられる。下記の参照を参照のこと。
注:ここでは、「よりも前に発生する」関係は全順序関係になっていると考えられる。また、modification order と矛盾しないとも考えられる。下記の参照を参照のこと。

## 備考
ラップされたストリームに一意に関連付けられたロックを保持しながら、ラップされたストリームのメンバ関数を呼び出すことができる。つまり、同じストリームを持つ他の`basic_syncbuf`オブジェクトに対してアトミックに転送することができる。
Expand Down
4 changes: 2 additions & 2 deletions reference/thread/jthread/join.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ void join();


## 同期操作
関連付けられたスレッドの完了は、`join()`メンバ関数の正常リターンと **同期する** 。
関連付けられたスレッドの完了は、`join()`メンバ関数の正常リターン**に対して同期する** 。

つまり、「`this`に関連付けられたスレッドT1上で行われる全処理の完了」は、
「`join()`メンバ関数を呼び出したスレッドT0上での同メンバ関数からの正常リターン」よりも **前に発生する** 。
「`join()`メンバ関数を呼び出したスレッドT0上での同メンバ関数からの正常リターン」**よりも前に発生する** 。


## 事後条件
Expand Down
4 changes: 2 additions & 2 deletions reference/thread/jthread/op_constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ jthread(jthread&&) noexcept; // (4) C++20


## 同期操作
- (2) : コンストラクタ呼び出しの完了は、`f`のコピーの呼び出し開始と同期する
- (2) : コンストラクタ呼び出しの完了は、`f`のコピーの呼び出し開始**に対して同期する**
新しいスレッドを生成し、[`INVOKE`](/reference/concepts/Invoke.md)`(DECAY_COPY(`[`std::forward`](/reference/utility/forward.md)`<F>(f)), DECAY_COPY(`[`std::forward`](/reference/utility/forward.md)`<Args>(args))...)`を実行する。ただし`DECAY_COPY`は同コンストラクタを呼び出したスレッド上にて評価される。また`f`のコピーの戻り値は無視される。
- `DECAY_COPY(x)`は `template <class T> typename std::decay<T>::type decay_copy(T&& v) { return` [`std::forward`](/reference/utility/forward.md)`<T>(v); }` と定義される。おおよそ、`x`が配列型なら先頭要素へのポインタ、`x`が関数型ならその関数ポインタ、`x`がコピーコンストラクト可能な型なら`x`からコピーされたオブジェクト、`x`がムーブコンストラクト可能な型なら`x`からムーブされたオブジェクトとなる。


## 同期操作
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始と**同期する**。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド`T1`上での`f`のコピーの呼び出し開始」よりも**前に発生する**。
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始**に対して同期する**。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド`T1`上での`f`のコピーの呼び出し開始」**よりも前に発生する**。


## 事後条件
Expand Down
2 changes: 1 addition & 1 deletion reference/thread/this_thread/sleep_for.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace this_thread {


## 同期操作
特に他操作と同期しない
特に他操作に対して同期する規定はない


## 例外
Expand Down
2 changes: 1 addition & 1 deletion reference/thread/this_thread/sleep_until.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace this_thread {


## 同期操作
特に他操作と同期しない
特に他操作に対して同期する規定はない


## 例外
Expand Down
2 changes: 1 addition & 1 deletion reference/thread/this_thread/yield.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace this_thread {


## 同期操作
特に他操作と同期しない
特に他操作に対して同期する規定はない


## 例外
Expand Down
4 changes: 2 additions & 2 deletions reference/thread/thread/join.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ void join();


## 同期操作
関連付けられたスレッドの完了は、`join()`メンバ関数の正常リターンと **同期する** 。
関連付けられたスレッドの完了は、`join()`メンバ関数の正常リターン**に対して同期する** 。

つまり、「`this`に関連付けられたスレッドT1上で行われる全処理の完了」は、
「`join()`メンバ関数を呼び出したスレッドT0上での同メンバ関数からの正常リターン」よりも **前に発生する** 。
「`join()`メンバ関数を呼び出したスレッドT0上での同メンバ関数からの正常リターン」**よりも前に発生する** 。


## 事後条件
Expand Down
2 changes: 1 addition & 1 deletion reference/thread/thread/op_constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ thread(thread&&) noexcept; // (4)


## 同期操作
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始と**同期する**。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド`T1`上での`f`のコピーの呼び出し開始」よりも**前に発生する**。
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始**に対して同期する**。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド`T1`上での`f`のコピーの呼び出し開始」**よりも前に発生する**。


## 事後条件
Expand Down
5 changes: 5 additions & 0 deletions working_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,8 @@ C++11以降対応については対応バージョンを明記します。バー
| weak ordering | 弱順序 |
| well-formed | 適格 |
| eligible | 資格のある |
| synchronizes with | に対して同期する (と同期するだと対称関係に見えるため) |
| happens before | よりも前に発生する |
| strongly happens before | よりも確実に前に発生する |
| sequenced before | よりも前に順序付けられる |
| indeterminately sequenced | 不定順で順序付けられる |
Loading