Closed21

CSAPP 第12章 並行プログラミング

bayamasabayamasa

プロセスによる並行プログラミング
fork, exec, waitpidを使ってプロセスを作成し、並行を実現する。

2つのクライアント、1つのサーバーという状態を考える。

  1. クライアントNo.1からサーバーはリクエストを受ける(受付ディスクリプタはfd = 3とする)
  2. サーバーはconnection用のディスクリプタを作成する ex) fd = 4
  3. サーバーはforkで子プロセスを作る。以降クライアント1はfd = 4を持つ子プロセスで処理を行う。
  4. 親プロセスはfd = 4を閉じ、子プロセスはfd = 3を閉じる。これによって待受fdは以前として3であり、複製プロセスは4となる
  5. クライアントNo.2からリクエストを受け取る
  6. サーバーはconnection用の先ほどとは異なる、ディスクリプタを作成する。 ex) fd = 5
  7. 先程と同様に、サーバーはforkをして子プロセスでクライアント2の処理を開始する。
bayamasabayamasa

プロセスはアドレス空間を共有しないため、親プロセスのある処理が子プロセスの処理に影響を及ぼすということがないのが特徴である。
これにより良くも悪くもお互いが干渉しない並行プログラミングができる

bayamasabayamasa

並行イベント駆動プログラミング

あるイベントの発火、IOデバイスによる入力などにおける割込などが発生したとき、それに基づくプログラムが起動する。
このプログラムは上から順番に実行されるプログラムとは異なり、制御フローが定まらないため競合などがおきないようにプログラムする必要があるので難しいが、自由度は他の並行プログラミングよりも高い

https://qiita.com/tabachain/items/bfb3573c0c6a37552579

bayamasabayamasa

スレッド
単一プロセス内部でリソース空間を分割する技術
メインスレッドとピアスレッドに分割され、スレッドコンテキストスイッチによって処理を移動する。
プロセスコンテキストスイッチよりも移動速度が早い

bayamasabayamasa

スレッドは独自のスレッドコンテクストをもつ

  1. thread id
  2. stack
  3. stack pointer
  4. PC
  5. 条件コード
bayamasabayamasa

スレッドスタックは他のスレッドから保護されていない。
つまり、他のスレッドからアクセスしようと思えばアクセスできてしまう。

bayamasabayamasa

セマフォ(semaphore)

排他制御のアルゴリズム
非負グローバル変数を定義して、PとVによって各スレッドの干渉を防ぐアルゴリズム
Pはproberen(テストする)、Vはverhogen(加算する)から来ている

bayamasabayamasa

基本的な動作としてはクリティカルセクションをPとVで囲む事によって実現する。

P(s)
cnt++
V(s)

semaphoreが0の時、スレッドの飽きがない状態。
0以外のときスレッドの飽きがある状態を表す。
Pによって現在のセマフォの値をチェックする。0以外のときはPの後の処理は競合しないと判断して、スレッド処理を開始する。もし0のときは他のスレッドの終了を待つ必要がある。
そのため、Pで処理を待機する。

Vによってスレッド処理の終了を実現する。V()によりセマフォを加算する。
そうすることで、もしセマフォが0だった場合、セマフォは1になる。
これにより、Pでチェックしていたセマフォが != 0となるのでPで待機していた側のスレッドの処理を開始することができる。

bayamasabayamasa

上記のように、スレッド共有変数を保護するために使われるセマフォは0と1で表現されるので、バイナリセマフォと呼ばれ、これはミューテックス(mutex)とも呼ばれる。
mutexに対してP操作を行うことは、mutexをロックすると呼ぶ。
mutexに対してV操作を行うことは、mutexをアンロックすると呼ぶ。

mutexをロックしたが、まだアンロックしていないスレッドはmutexを保持しているという。

bayamasabayamasa

バイナリで管理するのではなく、値のカウンタとして使われるセマフォは係数セマフォと呼ぶ。

bayamasabayamasa

並列処理は現代のマルチプロセッサが普及している時代において、マルチコアでの処理を実現することができるためとても有用である

bayamasabayamasa

スレッドセーフ
スレッドセーフとは、マルチスレッド環境において、あるコンピュータプログラムを複数のスレッドで並行して実行しても、問題が生じない仕様や設計になっていること。

bayamasabayamasa

関数によっては、スレッドアンセーフは関数の代わりにスレッドセーフの関数を持つ関数群が存在する。
rand →rand_r
gethostbyaddr → gethostbyaddr_r

suffixに_rを持つ関数はスレッドセーフである

bayamasabayamasa

リエントラント
リエントラントとは、あるプログラムやルーチンなどを実行中に、再び起動して実行し始めることができる性質。多重に起動されても狂いが生じず正しく動作する設計になっていることを表す。

つまりスレッドセーフな関数の中でも特にスレッドセーフなものを指す。
スレッドセーフな関数は同期処理などで待機などが必要なのに対し、リエントラント関数は親の呼び出しなどを考慮せず使用する事ができる。
→というのは嘘で暗黙的リエントラントの場合は考慮しないといけない

bayamasabayamasa

明示的リエントラント

関数の中で使用されている引数が値渡しで、ローカル変数がオート変数のみの場合、その関数は明示的リエントラントと呼び、どのように呼ばれてもリエントラント性を担保できる

bayamasabayamasa

暗黙的リエントラント

引数がポインタ渡しの場合は、必ずリエントラントであるとみなすことはできない。
関数の呼び出しもとに対して、影響を及ぼすため。

bayamasabayamasa

デッドロック

Pによる待機に対するVが存在しない時、そのプログラムの処理はPの処理の待機から抜けられない。
この並行プログラムにおける設計ミスをデッドロックと呼ぶ

bayamasabayamasa

並行プログラミングは並行にするごとに効率が上昇するというわけではない。
マルチコアの数や最適化によってその処理速度は変動する。

そのためいつでもベストプラクティスであるとはいえない。

このスクラップは2021/10/23にクローズされました