わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。

スレッドの同期(クリティカルセクション)

クリティカルセクションとは、スレッドの同期を行う為に使用します。 EnterCriticalSection()関数から、LeaveCriticalSection()関数を呼び出すまでの間は、他のスレッドに割り込まれること無く処理を行うことができます。 他のスレッドは、EnterCriticalSection()関数を呼び出した際に、他のスレッドが既にEnterCriticalSection()関数を呼び出していた場合は、 LeaveCriticalSection()関数が呼び出されるまで処理待ち状態になります。

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <process.h>
#include <windows.h>



// クリティカルセクション
CRITICAL_SECTION g_oCS;

// カウンタ
int g_nCounter = 0;



/*
	スレッドメイン処理
*/
unsigned __stdcall ThreadMain
(
	void* vpArguments
)
{
	std::wcout << L"スレッド開始 <- ThreadId = " << ::GetCurrentThreadId() << L" )" << std::endl;


	/*
		スレッドメイン処理
	*/
	BOOL bRun = TRUE;
	while( FALSE != bRun ) {

		std::wcout << L"クリティカルセクション待ち = " << ::GetCurrentThreadId() << std::endl;

		/*
			クリティカルセクション開始
				EnterCriticalSectionからLeaveCriticalSectionの間は、
				他のスレッドは、EnterCriticalSectionで待たされて、
				割り込む事ができません。
		*/
		::EnterCriticalSection( &g_oCS );

		// カウンタ+1
		if ( 10 > g_nCounter ) {
			g_nCounter++;
			std::wcout << L"カウンターを加算( " << g_nCounter << L" ) <- ThreadId = " << ::GetCurrentThreadId() << std::endl;
		}
		else {
			bRun = FALSE;
		}
		::Sleep( 1000 );

		// クリティカルセクション終了
		::LeaveCriticalSection( &g_oCS );
	}


	/*
		スレッドの終了
			この値はGetExitCodeThread()で取得できる
	*/
	std::wcout << L"スレッド終了 <- ThreadId = " << ::GetCurrentThreadId() << std::endl;
	::_endthreadex( 1234 );

	// 処理結果
	return( 0 );
}



/*
	スレッドの同期(クリティカルセクション)
*/
int _tmain
(
	  int argc
	, _TCHAR* argv[]
)
{
	/*
		std::wcoutのロケールを設定
		 これを設定するだけで、std::wcoutで日本語が表示される
		 ようになります。
	*/
	std::wcout.imbue( std::locale( "", std::locale::ctype ) );


	// クリティカルセクションの初期化
	::InitializeCriticalSection( &g_oCS );

	// スレッドハンドル
	HANDLE haThreads[] = {
		  NULL
		, NULL
		, NULL
	};

	// スレッドId
	UINT naThreadIds[] = {
		  0
		, 0
		, 0
	};

	// スレッドの生成
	for ( UINT nI = 0; nI < _countof( haThreads ); nI++ ) {

		// スレッド起動
		haThreads[ nI ] = (HANDLE)::_beginthreadex(
			  NULL					// SECURITY_ATTRIBUTES構造体
			, 0						// スタックサイズ( 0は呼び出し側と同じサイズ )
			, &ThreadMain			// スレッド関数
			, (void*)12345678		// スレッド関数への引数
			, 0						// 作成オプション( 0 / CREATE_SUSPENDED )
			, &naThreadIds[ nI ]	// スレッドId
		);
		std::wcout << L"スレッド起動 Id = " << naThreadIds[ nI ] << std::endl;
	}

	// スレッドの終了待ち
	::WaitForMultipleObjects( _countof( haThreads ), haThreads, TRUE, INFINITE );

	// スレッドハンドルの解放
	for ( UINT nI = 0; nI < _countof( haThreads ); nI++ ) {
		::CloseHandle( haThreads[ nI ] );
	}

	// クリティカルセクションの破棄
	::DeleteCriticalSection( &g_oCS );

	// 処理結果
	return( 0 );
}



実行結果

スレッド起動 Id = 23268
スレッド開始 <- ThreadId = 23268 )
スレッド起動 Id = 22960
スレッド起動 Id = 21816
スレッド開始 <- ThreadId = 22960 )
クリティカルセクション待ち = 23268
スレッド開始 <- ThreadId = 21816 )
クリティカルセクション待ち = 22960
カウンターを加算( 1クリティカルセクション待ち = 21816
 ) <- ThreadId = 23268
クリティカルセクション待ち = 23268
カウンターを加算( 2 ) <- ThreadId = 22960
クリティカルセクション待ち = 22960
カウンターを加算( 3 ) <- ThreadId = 21816
クリティカルセクション待ち = 21816
カウンターを加算( 4 ) <- ThreadId = 23268
クリティカルセクション待ち = 23268
カウンターを加算( 5 ) <- ThreadId = 22960
クリティカルセクション待ち = 22960
カウンターを加算( 6 ) <- ThreadId = 21816
クリティカルセクション待ち = 21816
カウンターを加算( 7 ) <- ThreadId = 23268
クリティカルセクション待ち = 23268
カウンターを加算( 8 ) <- ThreadId = 22960
クリティカルセクション待ち = 22960
カウンターを加算( 9 ) <- ThreadId = 21816
クリティカルセクション待ち = 21816
カウンターを加算( 10 ) <- ThreadId = 23268
クリティカルセクション待ち = 23268
スレッド終了 <- ThreadId = 22960
スレッド終了 <- ThreadId = 21816
スレッド終了 <- ThreadId = 23268






わびさびサンプルソース

WindowsやHTML5などのプログラムのサンプルコードやフリーソフトを提供します。