このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
複数のミューテックスで同じ条件変数が使用されています
同じ条件変数の同時待機が未定義の動作の場合に別々のミューテックスを使用しているスレッド
説明
このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされます。Polyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください。
この欠陥は、複数のスレッドが複数のミューテックスを使用して同じ条件変数を同時に待機している場合に発生します。スレッドは、関数 pthread_cond_timedwait
または pthread_cond_wait
を呼び出すことによって条件変数を待機します。これらの関数は条件変数とロックされたミューテックスを引数として取得し、条件変数はスレッドが条件変数を待機しているミューテックスにバインドされます。
チェッカーは、スレッドのいずれかにおける pthread_cond_timedwait
または pthread_cond_wait
の使用にフラグを設定します。同じ条件変数を待機しているスレッドを確認、別のミューテックスを使用するには、[結果の詳細] ペインで [イベント] 列を参照してください。
リスク
スレッドがミューテックスを使用して条件変数を待機すると、条件変数がそのミューテックスにバインドされます。別のミューテックスを使用して同じ条件変数を待機している他のスレッドは、POSIX 標準で定義されていない動作です。
修正方法
スレッドが同時に同じ条件変数を待機している場合は pthread_cond_timedwait
または pthread_cond_wait
に同じミューテックス引数を使用するか、ミューテックスごとに別々の条件変数を使用します。
例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #define Thrd_return_t void * #define __USE_XOPEN2K8 #define COUNT_LIMIT 5 static void fatal_error(void) { exit(1); } pthread_mutex_t mutex1; pthread_mutex_t mutex2; pthread_mutex_t mutex3; pthread_cond_t cv; int count1 = 0, count2 = 0, count3 = 0; #define DELAY 8 Thrd_return_t waiter1(void* arg) { int ret; while (count1 < COUNT_LIMIT) { if ((ret = pthread_mutex_lock(&mutex1)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex1)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count1 = %d\n", ++count1); if ((ret = pthread_mutex_unlock(&mutex1)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t waiter2(void* arg) { int ret; while (count2 < COUNT_LIMIT) { if ((ret = pthread_mutex_lock(&mutex2)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex2)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count2 = %d\n", ++count2); if ((ret = pthread_mutex_unlock(&mutex2)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t signaler(void* arg) { int ret; while ((count1 < COUNT_LIMIT) || (count2 < COUNT_LIMIT)) { sleep(1); printf("signaling\n"); if ((ret = pthread_cond_broadcast(&cv)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t waiter3(void* arg) { int ret; while (count3 % COUNT_LIMIT != 0) { if ((ret = pthread_mutex_lock(&mutex3)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex3)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count3 = %d\n", ++count3); if ((ret = pthread_mutex_unlock(&mutex3)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } int main(void) { int ret; pthread_t thread1, thread2, thread3; pthread_mutexattr_t attr; if ((ret = pthread_mutexattr_init(&attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex1, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex2, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex3, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_init(&cv, NULL)) != 0) { /* handle error */ fatal_error(); } if ((ret = pthread_create(&thread1, NULL, &waiter1, NULL))) { /* Handle error */ fatal_error(); } if ((ret = pthread_create(&thread2, NULL, &waiter2, NULL))) { /* handle error */ fatal_error(); } if ((ret = pthread_create(&thread3, NULL, &signaler, NULL))) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread1, NULL)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread2, NULL)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread3, NULL)) != 0) { /* Handle error */ fatal_error(); } while (1) { ; } return 0; }
この例では、別々のミューテックスを使用して各変数 count
を保護します。3 つすべての関数 waiter
が別々のミューテックスを使用して同じ条件変数 cv
を待機しているため、スレッドのいずれかの pthread_cond_wait
に対する呼び出しが成功すると、他の 2 つのスレッドの呼び出しが未定義になります。
チェッカーは、関数がスレッド、エントリポイント、または割り込みによって直接的または間接的に呼び出されなくても、関数 waiter3
の欠陥を報告します。解析では、関数 waiter3
が、その関数アドレスを介してメイン プログラムによって呼び出された、または、ソース コードが見当たらない不明なスレッドによって呼び出されたと見なされます。
1 つの修正方法として、同じ条件変数を待機するために使用される pthread_cond_wait
に対するすべての呼び出しに同じミューテックス引数を渡します。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #define Thrd_return_t void * #define __USE_XOPEN2K8 #define COUNT_LIMIT 5 static void fatal_error(void) { exit(1); } pthread_mutex_t mutex; pthread_cond_t cv; int count1 = 0, count2 = 0, count3 = 0; #define DELAY 8 Thrd_return_t waiter1(void* arg) { int ret; while (count1 < COUNT_LIMIT) { if ((ret = pthread_mutex_lock(&mutex)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count1 = %d\n", ++count1); if ((ret = pthread_mutex_unlock(&mutex)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t waiter2(void* arg) { int ret; while (count2 < COUNT_LIMIT) { if ((ret = pthread_mutex_lock(&mutex)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count2 = %d\n", ++count2); if ((ret = pthread_mutex_unlock(&mutex)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t signaler(void* arg) { int ret; while ((count1 < COUNT_LIMIT) || (count2 < COUNT_LIMIT)) { sleep(1); printf("signaling\n"); if ((ret = pthread_cond_broadcast(&cv)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } Thrd_return_t waiter3(void* arg) { int ret; while (count3 % COUNT_LIMIT != 0) { if ((ret = pthread_mutex_lock(&mutex)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_wait(&cv, &mutex)) != 0) { /* Handle error */ fatal_error(); } sleep(random() % DELAY); printf("count3 = %d\n", ++count3); if ((ret = pthread_mutex_unlock(&mutex)) != 0) { /* Handle error */ fatal_error(); } } return (Thrd_return_t)0; } /* void user_task(void) { (void)waiter3(NULL); } */ int main(void) { int ret; pthread_t thread1, thread2, thread3; pthread_mutexattr_t attr; if ((ret = pthread_mutexattr_init(&attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_mutex_init(&mutex, &attr)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_cond_init(&cv, NULL)) != 0) { /* handle error */ fatal_error(); } if ((ret = pthread_create(&thread1, NULL, &waiter1, NULL))) { /* Handle error */ fatal_error(); } if ((ret = pthread_create(&thread2, NULL, &waiter2, NULL))) { /* handle error */ fatal_error(); } if ((ret = pthread_create(&thread3, NULL, &signaler, NULL))) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread1, NULL)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread2, NULL)) != 0) { /* Handle error */ fatal_error(); } if ((ret = pthread_join(thread3, NULL)) != 0) { /* Handle error */ fatal_error(); } while (1) { ; } return 0; }
結果情報
グループ: 同時実行 |
言語: C | C++ |
既定値: オフ |
コマンド ライン構文: MULTI_MUTEX_WITH_ONE_COND_VAR |
影響度: Medium |
バージョン履歴
R2020a で導入
参考
欠陥の検出 (-checkers)
| 誤って失敗する可能性のある関数はループでラップされません
| 誤って起動する可能性のある関数はループでラップされません
| データ レース
| ロック解除されていません
| ロックされていません
| デッドロック
| 複数のスレッドが同じ条件変数を待機しています
トピック
外部の Web サイト
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)