(3)デッドロック(deadlock) [ 並列処理の不具合と対策 ]

 

前回のブログでは、排他処理区間を絞ると同時に2つのミューテックス変数を使うように改造した結果、再びプログラムが終わらなくなりました。今回はこの問題の調査と対策を行います。

 

終わらない並列処理の原因調査

 

 

まず、前回のシングルスレッドで試すに習って、mutex変数を1つにして動かしてみました。

 

上記のように片方をコメントアウトし、2つの関数が使用するミューテックス変数をひとつにしたところ、全く問題なくなりました。

しかし、2つの関数を比べると気になるとことがあります。ミューテックス変数のロック順が逆になっています。

 

使う変数の順に合わせてロックしているのですが、プログラムが停止する原因はここにあります。

printf()を使用して、どこで停止しているのか確認してみます。

 

コメントを外して、2つのミューテックス変数を使用するように戻し、マクロを書き換えて、ミューテックスのロック・アンロック処理に情報出力のprintf()を入れます。

このソースのプログラムを動かすと、topendの両関数がひとつめのミューテックス変数をロックしたところで停止しています。

 

ミューテックス変数unlock待ち状態、デッドロック ( deadlock )

 

 

両関数は相手と別の順で2つのミューテックス変数をロックしようとするため、お互いがタイミング良く(悪く)片方のミューテックス変数をロックした時に、相手のアンロック待ち状態に陥ってしまいました。

 

このような状態で両関数が動けなくなったことをデッドロックと呼びます。

 

デッドロック状態にあるプログラムについて、今回も gdb で確認しました

 

 

2つの並列動作関数は、スレッド で動いています。

 

top関数が76行目、end関数は101行目で止まっています。

 

問題の解決方法はロック順を揃えることです。

 

両関数のミューテックス変数ロック・アンロック順を揃えることで、このプログラムが正常に動作するようになりました。複数のミューテックス変数を使う際にロック順を決めておかないと、このような問題が発生します。

ところで、このプログラムで使用しているミューテックス・ロック関数は、pthread_mutex_lock() です。

この関数は指定のミューテックス変数がロック状態の時に、ロック中の関数がアンロックして自身がロックできるまで戻ってきません。そのために、デッドロックが発生したのですが、ロック中かどうかを確認する pthread_mutex_trylock という関数があり、こちらを使用するとロック状態を知ることができるのでデッドロックを起こさないような工夫ができます。しかし、失敗するとライブロックを発生することにもなります。

 

 次回は、pthread_mutex_trylock を使ってライブロックを起こしてみます。

 

ダウンロード
使用したプログラムソース(コンパイル方法はソースコメントを参照のこと)
1. sample1_3.c (並列処理、排他処理区間を絞ってデッドロック)
2. sample1_3_1.c (並列処理、ミューテックス変数を1つにしたら正常終了)
3. sample1_3_2.c (並列処理、printf()でlock状態を確認)
4. sample1_3_3.c (並列処理、ミューテックス変数のlock/unlock順を揃えたら正常終了)
Source_3.zip
zip ( 圧縮 ) ファイル 6.1 KB