プリンキピア

第6章インフラストラクチャーの抽象化層:オペレーティングシステム

Synchronization同期
Synchronization in concurrent programming is crucial for ensuring that multiple threads or processes can work together without interfering with each other’s operations on shared resources. Through mechanisms like locks, condition variables, and semaphores, developers can design systems that are both efficient and safe, avoiding issues such as data races and deadlocks. One way of coordinating multiple concurrent activities that are using shared state is synchronization, which groups operations together automatically to ensure cooperation between threads. To ensure that only one thread does a particular task at a time, we can use a program called mutual exclusion that prevents simultaneous access to a shared resource. A critical section is a piece of code that only one thread can execute at once. Also, only one thread at a time will get into this section of code. A critical section is the result of mutual exclusion. Critical sections and mutual exclusion are in fact two ways of describing the same thing. Critical sections are sequences of instructions that may get incorrect results if executed simultaneously. Mutual exclusion is required to ensure that a process cannot enter its critical section while another concurrent process is currently present in its critical section. Figure 6.24 illustrates a representation of two processes, process P1 and process P2. At Time 1, process P1 entered the critical section by printing on a shared printer. Process P1 will finish printing at Time 2. While process P1 is printing, process P2 is attempting to print, but the OS will block process P2 from printing until process P1 reaches Time 2.
英語のヒント
並行プログラミングにおける同期は、複数のスレッドやプロセスが、共有リソースに対する互いの操作を妨げずに協力できるようにするため、極めて重要である。開発者は、ロック、条件変数、セマフォなどの仕組みを通じて、データ競合やデッドロックを避け、効率と安全性を兼ね備えたシステムを設計できる。共有状態を使う複数の並行した活動を調整する方法の一つが、同期である。同期は、操作を自動的にまとめて、スレッド間の協力を確保する。ある時点で一つのスレッドだけが特定のタスクを行うようにするには、共有リソースへの同時アクセスを防ぐ、相互排除というプログラムを使える。クリティカルセクションは、一度に一つのスレッドしか実行できないコードの部分である。また、この部分へ入れるのは、一度に一つのスレッドだけである。クリティカルセクションは、相互排除の結果である。クリティカルセクションと相互排除は、実際には同じものを述べる二つの表現である。クリティカルセクションは、同時に実行すると誤った結果を生むおそれのある一連の命令である。別の並行プロセスが自分のクリティカルセクション内にいる間、あるプロセスが自分のクリティカルセクションへ入らないことを確保するために、相互排除が必要になる。図6.24は、P1とP2という二つのプロセスを表す。時点1で、P1は共有プリンターによる印刷を始め、クリティカルセクションに入った。P1の印刷は時点2で終わる。P1の印刷中にP2も印刷しようとするが、OSは、P1が時点2に達するまでP2の印刷をブロックする。
Figure 6.24

attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license · CC BY 4.0 · Source出典

Figure 6.24 Process P1 is using the printer starting from Time 1 and will finish printing at Time 2. Process P2 is trying to print while process P1 is printing. The OS will use mutual exclusion to prevent process P2 from starting until process P1 has ended. (attribution: Copyright Rice University, OpenStax, under CC BY 4.0 license)
図6.24 P1は時点1からプリンターを使い、時点2で印刷を終える。P1が印刷している間、P2も印刷しようとしている。OSは相互排除を使い、P1が終わるまでP2が開始しないようにする。(出典:著作権 Rice University、OpenStax。CC BY 4.0ライセンス)
A lock is a synchronization mechanism that is used to enforce mutual exclusion. A thread must acquire a lock before entering a critical section; if the lock is already held by another thread, the attempting thread will block until the lock becomes available. Another synchronization mechanism called a condition variable is used in conjunction with locks to allow threads to wait for certain conditions to become true. While a lock facilitates exclusive access to resources, a condition variable helps threads wait for specific states of the world.
英語のヒント
ロックは、相互排除を強制するための同期の仕組みである。スレッドは、クリティカルセクションへ入る前にロックを獲得しなければならない。別のスレッドがすでにロックを保持していれば、入ろうとするスレッドは、ロックを使えるようになるまでブロックされる。条件変数という別の同期の仕組みは、ロックと組み合わせて使い、特定の条件が真になるまでスレッドを待たせる。ロックはリソースへの排他的アクセスを助けるのに対し、条件変数は、周囲が特定の状態になるまでスレッドが待つことを助ける。
A classic example of a synchronization challenge is the producers/consumers problem, where producers generate data and place it into a buffer, and consumers remove data from the buffer for processing. In a producer/consumer scenario, a consumer might wait on a condition variable if the buffer is empty, and a producer might signal this variable once it adds an item to the buffer. The key concerns associated with this scenario include ensuring that producers don’t add data to a full buffer and that consumers don’t try to remove data from an empty buffer. Synchronization tools like locks and condition variables are used to solve these issues. A deadlock occurs when a set of threads are blocked forever, waiting for each other to release resources. This can happen, for example, if thread A holds lock 1 and waits to acquire lock 2, while thread B holds lock 2 and waits to acquire lock 1. Avoiding deadlocks requires careful design, such as acquiring locks in a consistent order or using timeout mechanisms.
英語のヒント
同期の課題の典型例が、生産者・消費者問題である。生産者はデータを作ってバッファーへ入れ、消費者は処理のためにバッファーからデータを取り出す。生産者・消費者の場面では、バッファーが空なら消費者が条件変数で待ち、生産者がバッファーへ項目を追加すると、この変数に通知を送ることがある。主な注意点は、生産者が満杯のバッファーへデータを追加しないことと、消費者が空のバッファーからデータを取り出そうとしないことを確保することである。この問題を解決するために、ロックや条件変数などの同期の道具を使う。デッドロックは、スレッドの集合が互いのリソース解放を待ち続け、永久にブロックされるときに起こる。たとえば、スレッドAがロック1を持ったままロック2の獲得を待ち、スレッドBがロック2を持ったままロック1の獲得を待つ場合である。デッドロックを避けるには、常に同じ順番でロックを獲得したり、タイムアウトの仕組みを使ったりする、慎重な設計が必要である。
Some other tools used in synchronization are:
同期で使うほかの道具には、次のようなものがある。
• Semaphores: Similar to locks, but allow multiple threads to access a finite number of resources
英語のヒント
• セマフォ:ロックに似ているが、有限個のリソースに複数のスレッドがアクセスすることを認める。
• Barriers: Enable multiple threads to wait until all have reached a certain point in their execution before any are allowed to proceed
英語のヒント
• バリア:どのスレッドも先へ進めるようになる前に、すべてのスレッドが実行中の特定の地点に達するまで、複数のスレッドを待たせる。
• Read-Write Locks: Allow multiple readers to access a resource concurrently but require exclusive access for writers
英語のヒント
• 読み書きロック:複数の読み手はリソースへ並行してアクセスできるが、書き手には排他的アクセスを要求する。
• Mailboxes: Dedicated channels that connect two processes directly, allowing data to be exchanged between them; mailboxes behave like queues but use semaphores for controlled automatic access, and operate in first in, first out (FIFO) order only.
英語のヒント
• メールボックス:二つのプロセスを直接結び、その間でデータを交換できるようにする専用チャネルである。メールボックスはキューに似た動作をするが、制御された自動アクセスのためにセマフォを使い、先入れ先出し(FIFO)の順序だけで動作する。