メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

MISRA C:2023 Dir 5.1

There shall be no data races between threads

R2024b 以降

説明

このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされますPolyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください

命令の定義

There shall be no data races between threads 1 .

根拠

以下の条件がすべて当てはまる場合は、データ レースが発生します。

  • 異なるスレッドでの 2 つのアクションが、同じメモリ位置の読み取りまたは変更を試行する。

  • 少なくとも 1 つのアクションが非アトミックである。

  • 演算の順序が固定されていない。

次のコードでは、異なるスレッドにある関数 foo() および bar() が、変数 data を変更します。これらのスレッドで実行順序は指定されておらず、いずれのアクションもアトミックではありません。両方のスレッドが同時に data の変更を試行して、データ レースが発生する可能性があります。このようなデータ レースにより、未定義の動作が発生します。

int64_t data = 0;

void foo() { /* thread 1*/
	while(1) {
		data = -1;
	}
}

void bar() { /* thread 2 */
	while(1) {
		data = 10;
	}
}
data の値は、スレッドの実行順序に依存します。data は 64 ビット整数であるため、この書き込み操作は 2 つの異なる 32 ビットの読み込み命令としてコンパイラにより実装される場合があります。その場合、最初の 32 ビットの読み込み操作の後に、foo() による data の書き込みが、bar() によって割り込まれる可能性があります。その結果、data の半分にされた 2 つの 32 ビットが異なるスレッドによって書き込まれ、data の値は予期しないものになる可能性があります。

データ レースは予期しない誤作動やメモリの破損を発生させる可能性があり、その場合、診断が困難なバグが生じます。データ レースを回避するには、スレッド間で共有されるオブジェクトへのアクセスを明示的に同期するための手順を踏む必要があります。次に例を示します。

  • 共有オブジェクトをアトミックとして宣言する。

  • ミューテックス オブジェクトを使用して、オブジェクトを共有するスレッドを同期する。

Polyspace 実装

次のいずれかの条件が満たされた場合、Polyspace はこの命令の違反を報告します。

  • 複数のタスクが保護されない操作を共通の変数に実行。両方のタスクが読み取り専用またはアトミック操作である場合、この命令には違反していません。

  • 複数のタスクが、特定の標準ライブラリ関数に対する保護されていない呼び出しを実行する。strerror()setlocale()getenv() などの関数に対する保護されていない呼び出しは、この命令の違反となる可能性があります。この命令の違反を発生させる可能性のある関数のリストについては、次を参照してください。CON33-C:Avoid race conditions when using library functions

Polyspace は、競合する操作のある共有変数ごとに 1 つの違反を報告します。

タスクとは、オプション [タスク] (-entry-points) を使用してエントリ ポイントとして指定する関数のことです。この命令を有効にしても、タスクを指定しなければ、Polyspace はこの命令の違反を報告しません。

この命令の違反を解決するには、コード内のスレッドを同期します。Polyspace は、C11 同時実行ライブラリを自動的に認識します。Polyspace でのスレッド作成とクリティカル セクションの自動検出を参照してください。

トラブルシューティング

ルール違反を想定していてもその違反が表示されない場合、コーディング規約違反が想定どおりに表示されない理由の診断を参照します。

すべて展開する

この例では、スレッド t1 および t2 によって予測できない順序でグローバル変数 shared_data が変更されるため、変数の値が予期しないものになります。Polyspace は違反を報告します。

#include <stdio.h>
#include <threads.h>

// Shared variable that will be modified by both threads
int shared_data = 0;  /*Noncompliant*/

// Worker function 1: Increments the shared variable
int worker1(void *arg) {
	for(int i = 0; i < 100000; ++i) {
		shared_data++; // Data race occurs here
	}
	return 0;
}

// Worker function 2: Decrements the shared variable
int worker2(void *arg) {
	for(int i = 0; i < 100000; ++i) {
		shared_data--; // Data race occurs here
	}
	return 0;
}

// Main function
int main() {
	thrd_t t1, t2;

	// Create worker threads
	if(thrd_create(&t1, worker1, NULL) != thrd_success) {
		// Failed to create thread 1
		return 1;
	}
	if(thrd_create(&t2, worker2, NULL) != thrd_success) {
		// Failed to create thread 2
		return 1;
	}

	// Wait for threads to finish
	thrd_join(t1, NULL);
	thrd_join(t2, NULL);

	// Print the final value of shared_data
	printf("Final value of shared_data: %d\n", shared_data);
	// The expected final value is 0, but due to the data race, the actual result may vary

	return 0;
}

この例を実行するには、worker1()worker2() をタスク、つまりエントリ ポイント関数として指定します。Polyspace ユーザー インターフェイスで、以下のオプションを指定します。

オプション仕様
マルチタスクを手動で構成 On
タスク (-entry-points)

worker1

worker2

または、コマンド ラインで以下のコマンドを使用します。

 polyspace-bug-finder -entry-points worker1,worker2
  
[結果の詳細] ペインで、競合する操作の各ペアをレビューできます。データ レース結果のレビューの詳細については、データ レースを参照してください。

この例では、スレッド t1 および t2 の両方が予測できない順序で再呼び出し不可能な標準ライブラリ関数 strerror() を呼び出します。Polyspace は違反を報告します。

#include <stdio.h>
#include <threads.h>
#include <errno.h>
#include <string.h>


// Worker function 1
int worker1(void *arg) {
	//...
    char *errmsg = strerror(errno); //Noncompliant
    //...
	return 0;
}

// Worker function 2
int worker2(void *arg) {
	//...
    char *errmsg = strerror(errno);
    //...
	return 0;
}

// Main function
int main() {
	thrd_t t1, t2;

	// Create worker threads
	if(thrd_create(&t1, worker1, NULL) != thrd_success) {
		// Failed to create thread 1
		return 1;
	}
	if(thrd_create(&t2, worker2, NULL) != thrd_success) {
		// Failed to create thread 2
		return 1;
	}

	// Wait for threads to finish
	thrd_join(t1, NULL);
	thrd_join(t2, NULL);

	return 0;
}

この例を実行するには、worker1()worker2() をタスク、つまりエントリ ポイント関数として指定します。Polyspace ユーザー インターフェイスで、以下のオプションを指定します。

オプション仕様
マルチタスクを手動で構成 On
タスク (-entry-points)

worker1

worker2

または、コマンド ラインで以下のコマンドを使用します。

 polyspace-bug-finder -entry-points worker1,worker2
  
[結果の詳細] ペインで、競合する関数呼び出しの各ペアをレビューできます。標準ライブラリ関数呼び出しのデータ レース結果のレビューについて詳しくは、標準ライブラリ関数呼び出しでデータ レースが発生しましたを参照してください。

チェック情報

グループ: 同時実行の考慮事項
カテゴリ: 必要
AGC カテゴリ: 必要

バージョン履歴

R2024b で導入


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.