ライブロックとは“動いているのだが進まない”という状況を指します。
たとえば、道を歩いていて向こうから来た人を避けようとするとき、相手が自分と同じ方向に動いてしまう。これを繰り返すような状況もライブロックとなります。
ライブロックは絶妙なタイミングで発生する
前回までのブログで使用したプログラムで、ライブロックを発生させてみました。
図のように、2つのスレッドが1つのミューテックス変数をロックし、2つ目のミューテックス変数もロックしようとしますが、もしロックできない時は1つ目をアンロックして逆の順で2つのロックを試みます。
2つロックできたら先へ進めますが、両スレッドが同じタイミングで順序を入れ替えてロックしようとすると、ライブロックに陥ります。
ライブロックを発生させたと簡単に書きましたが、実際に発生させるまで手間取りました。ライブロックは少しの記述変更で解消してしまいます。また、動作させる環境にも依存します。PCが異なるだけでなく、同時に動いている他のプログラムの状況にも影響を受けます。
このライブロックが発生したプログラムソースの一部を以下に示しますが、必ず発生するとは限りません。
試用した環境では、赤い区間にある usleep(1)が無ければライブロックしません(この記述があることで、1マイクロ秒停止します)。 また、コメントにある printf()を有効にしてもライブロックしなくなります。
プログラムは先に進まなくなったように見えます。しかし、本当にライブロックが発生しているかどうかを確認しなくてはなりません。
printfを使うと正常終了してしまうので、gdbを使ってデバッグしてみました。
ライブロックの確認
何度か停止させ、位置を確認すると、いつも同じ場所で停止しています。
これでは状態を確認できないので、プログラムの動作状況を確認できそうな変数の値を見てみました。
すると、ライブロックしていると思っていたループの外側にある変数値が変化しており、時々ライブロックループを抜けていることが判りました。
さらに調整
完全なライブロック状態が起こせるか、もう少し調整してみました。
その結果、片方のスレッドの usleep(1) をコメントアウトすることで、変化していた i の値が変わらなくなりました。
完全なライブロックをつくりだすのは大変そうです。
ここで起きていると思ったロック状態も、絶対にロック状態から抜け出せないわけではないかもしれません。
ライブロックは、完全に停止することは無くても処理が遅くなるという状況を引きおこすと考えても良いのかもしれません。
“動いているようだが、とても遅い“ というような状況が起きた時、ライブロックが発生しているのかもしれません。
次回は、ライブラックが発生したりしなかったり、少しずつ動く、そのような現象がなぜ起きるのかを考えてみます。
コメントをお書きください