排他制御に関する用語を大雑把に理解しよう「ロックとセマフォ」「共有ロックと排他ロック」「楽観的ロックと悲観的ロック」

# はじめに

"排他制御(exclusive control)"に関連した用語として以下のようなものがあり、何がなんだかよくわからなくなります。

共有ロック、排他ロック、セマフォ、ミューテックス、楽観的ロック、悲観的ロック

本記事ではそれぞれの用語の詳細には深く切り込まず、これらの用語がどういった視点で使われるものか、どこで制御が実装しているのか、に焦点をしぼります。

# はじめにまとめ

はじめにまとめの表を載せてしまいます。

|| 概要 | 実装場所 |
|---|----|----|
|ロック・セマフォ・Mutex|排他制御を実現する方式 | コンピュータプログラム全般 |
|共有ロック・排他ロック|排他制御の実現方式の1つである"ロック"の種類 | RDBMS、OSなど|
|楽観的ロック・悲観的ロック|アプリケーションの複数ユーザーによる競合に対するアプローチ | アプリケーション |

# 排他制御とは何か

そもそも排他制御とは何なのか。これは[Wikipedia](https://ja.wikipedia.org/wiki/%E6%8E%92%E4%BB%96%E5%88%B6%E5%BE%A1)の冒頭の説明によると以下のようです。

> 排他制御（はいたせいぎょ）とは、コンピュータ・プログラムの実行において、複数のプロセスが利用出来る共有資源に対し、複数のプロセスからの同時アクセスにより競合が発生する場合に、あるプロセスに資源を独占的に利用させている間は、他のプロセスが利用できないようにする事で整合性を保つ処理の事をいう。

「目的地Xへ向かっているAさんが乗車しているタクシーに、Bさんが突然乗り込んできて目的地をYにするよう運転手さんに頼んでしまう」
そんなことが起こらないように制御する仕組みが排他制御となります。
(AさんBさんが各プロセス、タクシーの目的地という情報が資源にあたります)

**資源**という用語は抽象的です。資源は物理メモリ領域、仮想メモリ領域、ファイル、DBのテーブルのレコード、と処理によって様々です。
排他制御は特にデータベース専用の用語ではなく、コンピュータ・プログラムの実行に関して用いられます。

# 排他制御を実現する方式

以下の3つのワードは**排他制御を実現する方式**です。

0. ロック (Lock)
0. セマフォ (Semaphore)
0. ミューテックス (Mutex)

これらの用語は、ある資源の整合性を保つことを実現するためのアプローチです。

## ロック (Lock)

ロックとは"データの読み書きを一時的に制限すること"です。

ロックには**種類(モード)**があります。共有ロック、排他ロックなどです。

この2種類の説明は「共有ロックvs排他ロック」で後述。

## セマフォ (Semaphore)

セマフォとは"対象資源のうち現在利用可能な数を表す**値**"です。

この値をプロセスが上げたり下げたりすることで資源の使用中、解放を他プロセスに伝えます。

また、セマフォという仕組みは排他制御だけではなく、**プロセス間の同期**を実現するためにも利用されます。


## ミューテックス (Mutex)

ミューテックスとは簡単に説明すると、セマフォの値において0または1しか利用しない**ようなもの**です。(正確にはそうではないみたいです)。
これにより、1プロセスのみが対象資源を占有できるようになります。

セマフォの中にもバイナリセマフォと呼ばれるミューテックスと同様に0または1のみの数を持つセマフォがあります。[こちらのQuoraの記事](https://www.quora.com/What-is-the-difference-between-a-mutex-and-a-semaphore)によると以下の様な回答があります。

> (中略)Thus, a mutex can only be used to maintain atomicity whereas a semaphore can be used for both ordering and atomicity.

つまり、ミューテックスは整合性(atomicity)のみを保証するのに対して、セマフォは整合性に加えてプロセス間に対象リソース操作の順序性(odering)(つまり上述の"プロセス間同期")も保証する役割も持つことができます。

# 共有ロックと排他ロック

ロックには種類(モード)があります。代表的なものが以下の共有ロックと排他ロックです。

共有ロック → 他プロセスがREAD(読み込み)するのは許すがUPDATE(更新)するのは許さないロック。
排他ロック → 他プロセスがREADするのもUPDATEするのも許さないロック。

これらロックの制御を実装しているのがRDBMS(MySQLやPostgreSQL)のミドルウェアやOSです。
RDBMSはDBのテーブル、レコードをロックし、OSはファイルなどをロックします(ファイルロック)。

# 楽観的ロックと悲観的ロック

## はじめに

楽観的ロックと悲観的ロックというのは、**アプリケーション実装者の立場による区別**です。具体的には**アプリケーションの複数ユーザーがあるデータを同時に更新する**という状況に対するアプローチの区別です。
少なくともDBやRDBMSがメインで提供する機能ではありません(※)。
このポイントがわかると混乱しないで済みます。

※ RDBMSによっては楽観的ロック、悲観的ロックの機能を提供するものもあるようです。[IBMのsolidDB](https://www.ibm.com/support/knowledgecenter/en/SSPK3V_7.0.0/com.ibm.swg.im.soliddb.sql.doc/doc/pessimistic.vs.optimistic.concurrency.control.html)など。

## 楽観的ロック

楽観的ロックではデータ読み出し時に内容をキャッシュしておき、データを更新する直前に、他のユーザーによって更新されていないかどうかをチェックします。そして他のユーザーによってすでに更新されていた場合、更新処理をキャンセルします。

この制御を実装するのは、アプリケーション実装者です。

近年では、**各言語のORマッパーがこの制御の実装をサポート**しています。
([JavaのDoma](https://msdn.microsoft.com/en-us/library/system.data.linq.objectchangeconflict(v=vs.110).aspx)、[C#のLinq to SQL](https://msdn.microsoft.com/en-us/library/system.data.linq.objectchangeconflict(v=vs.110).aspx)、[Ruby on RailsのActiveRecord](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html)などで楽観的ロック時の例外が用意されています。)

## 悲観的ロック

悲観的排他制御では、更新対象のデータ読み出しの時点で、他のユーザーがそのデータに触れないようロックをします。

このとき、**ロックのモード(共有ロック、排他ロック)の選択はアプリケーション実装者に委ねられます**。

# 参考

* https://www.ibm.com/support/knowledgecenter/SSPK3V_7.0.0/com.ibm.swg.im.soliddb.sql.doc/doc/shared.exclusive.and.update.locks.html
* https://codezine.jp/article/detail/6764
* https://stackoverflow.com/a/18806907
* https://stackoverflow.com/questions/129329/optimistic-vs-pessimistic-locking
* https://www.quora.com/What-is-the-difference-between-a-mutex-and-a-semaphore