Windows の win32 における代表的な同期処理には以下の3つの手法があります。
ここでは下記から「1. Critical
Section」について記載します。
1. CriticalSection を使ってみる
2. ***
3. ***
[概要]
まずは CriticalSection を使用するシンプルな例を示します。
[評価環境]
コンパイラ : | Visual Studio 2019 pro., | Version 16.4.4 |
OS: | Windows10 home, | Version 1909 |
最初に、うまく動かない例を示します。そして次に、CriticalSectionを使用することで意図通りに動作する例を示します。
こちら、BadExample.cpp はうまく動かない例です。
4つのスレッドがそれぞれ25,000回のインクリメントをするので、最後に count
は100,000になることを期待するプログラムです。しかし同期処理がないために意図する動作をしない、という例です。
[BadExample.cpp]
#include <iostream> // std::cout, std::endl
#include <tchar.h> // _tmain
#include <thread> // std::thread
// グローバル変数
volatile long count = 0;
void CountThread(const size_t iterations)
{
int x;
for (size_t i = 0; i < iterations; ++i)
{
x = count;
// 問題を発生させにくい場合は次の行のコメントアウトを外してください。
// std::this_thread::yield(); // スレッドの処理明け渡し。c++11。
x++;
count = x;
}
}
int _tmain(int argc, char* argv[])
{
const size_t numThreads = 4;
std::thread countThreads[numThreads];
/*========*/
/* 処理部 */
/*========*/
// スレッドを4つ作成
for (size_t i = 0; i < numThreads; ++i)
{
countThreads[i] = std::thread(CountThread, 25000);
}
// 4つのスレッドが終わるのを待つ
for (size_t i = 0; i < numThreads; ++i)
{
countThreads[i].join();
}
// 4つのスレッドが終了したのちの count の値をチェック
std::cout << "count = " << count << std::endl;
/*========*/
/* 後処理 */
/*========*/
// [Enter]キー 入力待ち
{
std::cout << "HIT [Enter] KEY ";
int ch = getchar();
}
return EXIT_SUCCESS;
}
期待する 100,000 に対して 65,703 までしかカウントアップできませんでした。これはうまく動作しない例です。
この値はプログラムを実行するたびに代わります。
次に CriticalSection により同期処理を加えた例を示します。
#include <windows.h> // CRITICAL_SECTION, InitializeCriticalSection, DeleteCriticalSection, EnterCriticalSection, LeaveCriticalSection
#include <iostream> // std::cout, std::endl
#include <tchar.h> // _tmain
#include <thread> // std::thread
#include <atomic> // std::atomoic
// グローバル変数
volatile long count = 0;
CRITICAL_SECTION critSec;
void CountThread(size_t iterations)
{
int x;
for (size_t i = 0; i < iterations; ++i)
{
EnterCriticalSection(&critSec);
{
x = count;
x++;
count = x;
}
LeaveCriticalSection(&critSec);
}
}
int _tmain(int argc, char* argv[])
{
const size_t numThreads = 4;
std::thread countThreads[numThreads];
InitializeCriticalSection(&critSec);
{
// スレッドを4つ作成
for (size_t i = 0; i < numThreads; ++i)
{
countThreads[i] = std::thread(CountThread, 25000);
}
// 4つのスレッドが終わるのを待つ
for (size_t i = 0; i < numThreads; ++i)
{
countThreads[i].join();
}
// 4つのスレッドが終了したのちの count の値をチェック
std::cout << "count = " << count << std::endl;
}
DeleteCriticalSection(&critSec);
/*========*/
/* 後処理 */
/*========*/
{
std::cout << "HIT [Enter] KEY ";
int ch = getchar();
}
return EXIT_SUCCESS;
}
今度はちゃんと 100,000 になりました。
[概要]
[評価環境]
コンパイラ : | Visual Studio 2019 pro., | Version 16.4.0 |
OS: | Windows10 home, | Version 1909 |
[プログラムソース "***.cpp"]
サンプルプログラム ダウンロード
記載: