ロックされたミューテックスの破棄
タスクによるロックされた状態のミューテックスの破棄の試み
説明
このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされます。Polyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください。
この欠陥は、ミューテックスがロックされた後 (そのロックが解除される前に) タスクがミューテックスを破棄した場合に発生します。このロックと破棄は、同じタスクで行われることも、異なるタスクで行われることもあります。
リスク
ミューテックスは、共有変数を同時アクセスから保護するためにロックされます。ミューテックスがロックされた状態で破棄される場合、この保護が適用されません。
修正方法
この欠陥を修正するには、ミューテックスのロックを解除した後のみ破棄します。適切な設計は、以下のとおりです。
ミューテックスを使用するスレッドを作成する "前" にミューテックスを初期化します。
作成したスレッドに加わった "後" にミューテックスを破棄します。
[結果の詳細] ペインに、ミューテックスのロックと破棄の 2 つのイベントと、そのイベントを開始したタスクが表示されます。ソース コード内の対応する行に移動するには、そのイベントをクリックします。
例
#include <pthread.h>
pthread_mutex_t lock1;
pthread_mutex_t lock2;
pthread_mutex_t lock3;
void t0 (void) {
pthread_mutex_lock (&lock1);
pthread_mutex_lock (&lock2);
pthread_mutex_lock (&lock3);
pthread_mutex_unlock (&lock2);
pthread_mutex_unlock (&lock1);
pthread_mutex_unlock (&lock3);
}
void t1 (void) {
pthread_mutex_lock (&lock1);
pthread_mutex_lock (&lock2);
pthread_mutex_destroy (&lock3);
pthread_mutex_unlock (&lock2);
pthread_mutex_unlock (&lock1);
}
この例では、タスク t0 がミューテックス lock3 をロックした後、タスク t1 がこれを破棄する可能性があります。このような破棄は、以下のような順序でイベントが発生した場合に発生します。
t0がlock3をかけます。t0がlock2を解除します。t0がlock1を解除します。t1がt0によって解除されたロックlock1をかけます。t1がt0によって解除されたロックlock2をかけます。t1がlock3を破棄します。
説明を簡単にするために、この例では同時実行の自動検出と手動検出を組み合わせて使用します。タスク t0 と t1 は、オプション タスク (-entry-points) を使用して、手動でエントリ ポイントに指定されます。本ソフトウェアによって自動検出されるプリミティブ型 pthread_mutex_lock と pthread_mutex_unlock を使用して、クリティカル セクションを実装します。実際のエントリ ポイントの指定 (スレッド作成) には、pthread_create などのプリミティブ型を使用します。次の例では、pthread_create を使用すると、この欠陥がどのように現れる可能性があるかを示します。
lock3 のロックと破棄は、lock1 と lock2 によって定められたクリティカル セクション内部で行われていますが、ロック解除が外部で行われています。考えられる 1 つの修正方法として、ミューテックスの破棄と同じクリティカル セクションにロックとロック解除のペアを配置します。以下のいずれかのクリティカル セクションを使用します。
lock1のみによって定められるクリティカル セクション。lock1とlock2によって定められるクリティカル セクション。
修正した以下のコードでは、ロックとロック解除のペアと破棄が lock1 と lock2 によって定められるクリティカル セクションに配置されます。t0 が lock1 と lock2 をかけたとき、t1 はこのロックの解除を命令 pthread_mutex_destroy (&lock3); が実行されるまで待たなければはなりません。したがって、t1 は、ロックされた状態のミューテックス lock3 を破棄できません。
#include <pthread.h>
pthread_mutex_t lock1;
pthread_mutex_t lock2;
pthread_mutex_t lock3;
void t0 (void) {
pthread_mutex_lock (&lock1);
pthread_mutex_lock (&lock2);
pthread_mutex_lock (&lock3);
pthread_mutex_unlock (&lock3);
pthread_mutex_unlock (&lock2);
pthread_mutex_unlock (&lock1);
}
void t1 (void) {
pthread_mutex_lock (&lock1);
pthread_mutex_lock (&lock2);
pthread_mutex_destroy (&lock3);
pthread_mutex_unlock (&lock2);
pthread_mutex_unlock (&lock1);
}
#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 4
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
void atomic_operation(void);
void *do_create(void *arg) {
/* Creation thread */
pthread_mutex_init(&lock, NULL);
pthread_exit((void*) 0);
}
void *do_work(void *arg) {
/* Worker thread */
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_exit((void*) 0);
}
void *do_destroy(void *arg) {
/* Destruction thread */
pthread_mutex_destroy(&lock);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Thread that initializes mutex */
pthread_create(&callThd[0], &attr, do_create, NULL);
/* Threads that use mutex for atomic operation*/
for(i=0; i<NUMTHREADS-1; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
/* Thread that destroys mutex */
pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL);
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
pthread_exit(NULL);
}この例では、4 つのスレッドが作成されています。スレッドは異なるアクションに割り当てられています。
1 番目のスレッド
callThd[0]がミューテックスlockを初期化します。2 番目スレッド
callThd[1]と 3 番目のスレッドcallThd[2]が、ミューテックスlockによって保護されるアトミック操作を実行します。4 番目のスレッド
callThd[3]が、ミューテックスlockを破棄します。
スレッドは互いに割り込まれる可能性があります。したがって、2 番目または 3 番目のスレッドがミューテックスをロックした直後に、4 番目のスレッドがこれを破棄する可能性があります。
考えられる 1 つの修正方法として、スレッドの開始ルーチン外部の main 関数でミューテックスを初期化および破棄します。スレッドではアトミック操作のみを実行します。ミューテックスの初期化と破棄を行うスレッドは必要なくなるため、スレッドを 2 つ減らす必要があります。
#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 2
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
void atomic_operation(void);
void *do_work(void *arg) {
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Initialize mutex */
pthread_mutex_init(&lock, NULL);
for(i=0; i<NUMTHREADS; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
/* Destroy mutex */
pthread_mutex_destroy(&lock);
pthread_exit(NULL);
}別の修正方法として、2 番目のミューテックスを使用してロックとロック解除のペアを破棄から保護します。修正した次のコードでは、ミューテックス lock2 を使用してこの保護を実現しています。2 番目のミューテックスは、スレッドの開始ルーチン外部の main 関数で初期化されています。
#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 4
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
pthread_mutex_t lock2;
void atomic_operation(void);
void *do_create(void *arg) {
/* Creation thread */
pthread_mutex_init(&lock, NULL);
pthread_exit((void*) 0);
}
void *do_work(void *arg) {
/* Worker thread */
pthread_mutex_lock (&lock2);
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_mutex_unlock (&lock2);
pthread_exit((void*) 0);
}
void *do_destroy(void *arg) {
/* Destruction thread */
pthread_mutex_lock (&lock2);
pthread_mutex_destroy(&lock);
pthread_mutex_unlock (&lock2);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Initialize second mutex */
pthread_mutex_init(&lock2, NULL);
/* Thread that initializes first mutex */
pthread_create(&callThd[0], &attr, do_create, NULL);
/* Threads that use first mutex for atomic operation */
/* The threads use second mutex to protect first from destruction in locked state*/
for(i=0; i<NUMTHREADS-1; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
/* Thread that destroys first mutex */
/* The thread uses the second mutex to prevent destruction of locked mutex */
pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL);
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
/* Destroy second mutex */
pthread_mutex_destroy(&lock2);
pthread_exit(NULL);
}結果情報
| グループ: 同時実行 |
| 言語: C | C++ |
| 既定値: オフ |
コマンド ライン構文: DESTROY_LOCKED |
| 影響度: Medium |
バージョン履歴
R2016b で導入
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)