プロセスIDは一意じゃない

2020年2月14日バグの巣

プロセスIDは時間を跨ぐと一意性は崩れます

Windows や Linux などのマルチプロセス環境(マルチタスクとも言いますね)で開発をしていると、プロセスIDを使う場面があります。プロセスIDとは OS が管理している「ある時点でプロセスを一意に識別するための番号」なのですが、時間を跨ぐと一意性は保証されません。ここをうっかり忘れていると、思わぬバグが住み着いてしまいますので、要注意です。

一意性のあるID番号は自分で作るのは面倒です

ソフトウエアの開発でマルチタスク環境での開発をしていると、同一の処理や同一の資源が複数ある時に、個々の処理や資源を識別するための固有の識別番号が必要になる事があります。英語だと Identification Number なので略してID番号と呼ぶ事も多いですね。固有の番号ならばどんな作り方をしても良いので、必要なID番号の個数が予め決まっているならば、適当な整数を割り当てても問題ありません。 

でも、場合によっては必要な個数が決まっていない時もあります。そのような場合に1ずつ増える整数をID番号に使ったりすると、整数がロール―オーバーした場合に同じ値が出現して一意性が崩れてしまうので、ID番号としては不適切になります。乱数なんかを使うと、それこをランダムに発生する数字なので同じ値が生成されて一意性が崩れる可能性もあって、これもID番号には不適切です。プログラムの中で自分で固有の識別番号を作るというのは、案外と面倒なものです。

システムのプロセスIDが使えるような気が・・・

自分でID番号を生成するのは面倒なので、システムで何か使える物が無いかと見回せば、Windows や Linux をOSに使っている場合には、プロセスIDという物が在るのに気づきます。OSが提供するIDなので、その値を獲得するシステムコールも準備されています。 名前にも IDとついているので、識別番号としての一意性にも問題はありません。何といってもOSが提供するID番号なのでその一意はOSが保証しているので安心です。

なので、ID番号としてこのプロセスIDを使うという考え方は、割と普通に思いつく解決策だと思います。

プロセスIDが一意なのはある時点だけです

しかし、プロセスIDをプログラムの中でIID番号として使う時には、少し注意が必要です。プロセスIDの説明を注意して読むと「ある時点で存在するプロセスを一意に識別するために用いられる」と書いてあります。この「ある時点で」という但し書きをよく理解していないと、バグがすり寄ってきます。

OSがプロセスIDの一意性を保証するのがある時点に限定されているという事は、言い方を変えると時間が経てばプロセスIDは一意性を保証していない、という事です。プロセスID は、OS がプロセスを管理するために使っているID番号なので、「今この瞬間に存在しているプロセスを一意に識別できる番号」であれば良いのです。なので、終了したプロセスが使っていたプロセスIDをその後に生成されたプロセスに割り当てる、という事は普通に発生します。

もう少し具体的に見ていきましょう。マルチプロセスのOSでは、プロセスは動的に生成されたり終了したりしていて、生成される時にプロセスIDが割り当てられます。例えばプロセス-Aが生成された時に、OSはその時点で一意性のあるプロセスIDとして「ID番号-1」をそのプロセスAに割り付けます。そして、プロセスAが終了した時にはそのプロセスに割り付けられていたプロセスIDである「ID番号-1」は解放されます。

「ID番号-1」というプロセスIDがプロセス-Aから解放された後に、また別のプロセス-Bが生成されると、OS は既に解放されている「ID番号-1」をプロセス-B にプロセスIDとして割り当てる場合もあります。そうすると、プロセス-A とプロセス-B とに同じプロセスID「ID番号-1」が割り当てられる事になります。 でも、プロセス-B が生成された時にはプロセス-A は既に終了していて存在しないので、ある時点でのプロセスIDが重複する事は無く、「その時点でのプロセスIDの一意性」は保たれているので、OSとしては問題ありません。

時間の流れに沿って処理をするプログラムでは問題です

 OSとしてはプロセスIDの一意性は保たれていて問題無いのですが、プログラムでこのプロセスIDを何かのID番号に利用している場合には、使い方によって問題が起きます。何かのID番号としてある時点でのプロセスのプロセスIDを所得して、それを記憶して利用するようなプログラムを組んでいたとします。プロセス-A とプロセス-B とは別のプロセスなので当然別のプロセスIDが割り振られるだろう、と想定してプログラムを作っていると、プロセス-Aとプロセス-B との生成/終了のタイミングによっては、両方のプロセスのプロセスIDが同じ値の「ID番号-1」になってしまう事も、起こり得ます。

一意の識別番号として使っていたはずの ID番号が重複していると、プログラムの処理がおかしくなってしまいます。このID番号の重複がバグとして嫌らしいのは、問題が起きる確率が非常に低くて多くの場合は正常に動いてしまう事です。正常に動いてしまうので、社内のテストでバグとして見つけられる可能性が低く、市場にでて本番稼働をしてから、ぽつぽつと何かおかしな動きが散見される、という事が起きます。そして、原因を調べようとしても再現性に乏しくて、なかなか調査が進まないという事態になってしまいます。

プロセスIDが一意なのはある瞬間に限られている、という事を忘れてしまうと、このようなバグを呼びy干せてしまう事もあるので、皆さんも注意してください。

バグの巣に戻る