[C++] タイマー、それもコンソール・アプリケーションで別スレッド立てて (C#プログラマ向け)

囲碁プログラムを作ろうと思うんだが、
C#プログラマーには タイマー１個使うにも C++ はよくわからん。
作るのは　コマンドライン打ち込みができる　コンソール・アプリケーションだ。

あと、Unityなら初期装備のユニット・テストも　Visual Studio 2015 C++ では　なんか導入方法が分からんかった。困ったもんだ。

とりあえず　タイマーを自作してみた。
関係ないコードを削って　抜粋してみる。削りそこなうかもしれないが……。

# 1段階目
## Console_Kifuwarabe.cpp

```C++
// Console_Kifuwarabe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include "UtilFile.h"
#include "UtilTimer.h"

/**
 * 指定時間間隔で実行したい処理を書くクラス
 */
class Worker : public DefaultWorker
{
public:
	Worker() : DefaultWorker()
	{
		std::cout << "サブクラスのコンストラクター、呼んでるのかだぜ☆（＾～＾）？" << std::endl;
	}

	void OnStep()
	{
		std::cout << "別スレッドで実行中だぜ☆（＾▽＾）ｖ" << std::endl;
		// TODO: ここにやりたい処理を書く
	}
};

int main()
{
	// スレッドテスト
	UtilTimer timer;
	Worker* pWorker = new Worker();
	// スレッドスタート。
	timer.Start(pWorker,1000);
	// 10秒経ったら　スレッドを止めよう☆（＾～＾）
	UtilTimer::Sleep_Milliseconds(5000L);
	std::cout << "5秒経ったけど、動いてんの☆（＾～＾）？" << std::endl;
	UtilTimer::Sleep_Milliseconds(5000L);
	timer.Break_Force();
	delete pWorker;

	// 横軸はアルファベットにする☆（１桁で済む） Iを飛ばすのは　少なくともわたしはグニュー碁1.2(1995年)では見かけた昔からある習慣☆ 縦棒と区別するぜ☆（＾▽＾）
	std::cout	<< "  |ABCDEFGHJKLMNOPQRST|" << std::endl
				<< "--+-------------------+" << std::endl
				<< " 1|                   |" << std::endl
				<< " 2|                   |" << std::endl
				<< " 3|                   |" << std::endl
				<< " 4|                   |" << std::endl
				<< " 5|                   |" << std::endl
				<< " 6|                   |" << std::endl
				<< " 7|                   |" << std::endl
				<< " 8|                   |" << std::endl
				<< " 9|                   |" << std::endl
				<< "10|                   |" << std::endl
				<< "11|                   |" << std::endl
				<< "12|                   |" << std::endl
				<< "13|                   |" << std::endl
				<< "14|                   |" << std::endl
				<< "15|                   |" << std::endl
				<< "16|                   |" << std::endl
				<< "17|                   |" << std::endl
				<< "18|                   |" << std::endl
				<< "19|                   |" << std::endl
				<< "--+-------------------+" << std::endl
				<< "何かボタンを押せだぜ☆（＾▽＾）" << std::endl;
	getchar();
	//system("pause");

    return 0;
}
```

## UtilTimer.h

```C++
#pragma once
#include <iostream>
#include <fstream>
#include <atomic>
#include <thread>
#include <chrono>

/**
* 指定時間間隔で実行したい処理を書くクラス
*/
class DefaultWorker
{
public:
	DefaultWorker()
	{
		std::cout << "スーパー・クラスのコンストラクターはこれだけど……☆（＾～＾）" << std::endl;
	}

	virtual void OnStep()
	{
		std::cout << "このOnStep()は実行してはいけないぜ☆（＞＿＜）" << std::endl;
		// なんにもしないぜ☆（＾▽＾）
	}

	/**
	 * ファンクターというのは、クラス名の後ろに() 演算子を付けたものです。
	 * ファンクターの引数は 無しにしておいてください。
	 */
	virtual void operator()()
	{
		std::cout << "スーパークラスのファンクターなんか呼んでんの☆（＾～＾）？" << std::endl;
		// なんにもしないぜ☆（＾▽＾）
	}
};

/**
 * スレッドを立て、テキストファイルの内容が更新されていないか確認します。
 * 参照 : 「c++で一定間隔で関数を実行させたい」 (teratail) https://teratail.com/questions/27449
 * 参照 : 「std::thread::thread」 (C++言語の入門サイトです) http://kaworu.jpn.org/cpp/std::thread::thread
 * 参照 : 「std::this thread::sleep for」 (C++言語の入門サイトです) http://kaworu.jpn.org/cpp/std::this_thread::sleep_for
 * 参照 : 「C++1z ラムダ式での*thisのコピーキャプチャ」 (Faith and Brave - C++で遊ぼう) http://faithandbrave.hateblo.jp/entry/2016/04/27/191209
 * 参照 : 「C++ で継承したときにサブクラスのメンバ関数を呼ぶためには virtual をつけて仮想関数にする」 (sotarokのお勉強) http://d.hatena.ne.jp/strkpy/20100401/1270133069
 */
class UtilTimer
{
public:
	UtilTimer();
	~UtilTimer();

	/**
	 * スレッドを開始します。
	 */
	void Start(DefaultWorker* pWorker, long milliseconds);
	/**
	 * スタートさせたスレッドが動いている間は、処理を先に進ませません。
	 */
	void Block();
	/**
	 * 処理の途中でも、強制的にスレッドを終了します。
	 */
	void Break_Force();

	/**
	 * （このクラスの持つスレッドではなく）この関数を呼び出したスレッドを、指定ミリ秒停止させます。
	 * ネームスペースを切るのがめんどくさいので　このクラスに置いている。
	 */
	static void Sleep_Milliseconds(long milliseconds);

protected:
	std::thread m_thread1;
	/**
	 * スレッドを停止しても、処理のループは動き続けているようだったので、
	 * このフラグを偽にすることで、スレッドの中のループから抜けさせます
	 */
	bool m_alive;
	/**
	 * 別スレッドで実行したい処理を書いたメソッドを持っています。
	 */
	DefaultWorker* m_pWorker;
};
```

## UtilTimer.cpp

```C++
#include "stdafx.h"
#include "UtilTimer.h"

UtilTimer::UtilTimer()
{
}


UtilTimer::~UtilTimer()
{
}

void UtilTimer::Start(DefaultWorker* pWorker, long milliseconds)
{
	m_alive = true;
	m_pWorker = pWorker;
	m_thread1 = std::thread([=,&milliseconds] {
		// 処理と処理の間を n 秒以上空ける。（毎回 n 秒間隔保障なので、n 秒毎に定期的にスタートされるという意味ではない）
		const std::chrono::milliseconds interval(milliseconds);
		while (this->m_alive) {
			
			auto start = std::chrono::system_clock::now();

			// 処理が書かれたメソッドを呼び出す
			this->m_pWorker->OnStep();

			auto end = std::chrono::system_clock::now();
			auto elapsed = end - start;
			std::cout << "elapsed.count()=[" << elapsed.count() << "]" << std::endl;

			// 毎回、インターバル時間のスリープを保障
			if (elapsed < interval) {
				std::this_thread::sleep_for(interval - elapsed);
			}
		}

		std::cout << "finished." << std::endl;
	});
}

void UtilTimer::Block()
{
	// スタートさせたスレッドが終了するまで、これ以上進まない。
	m_thread1.join();
	// スレッドを止めるか、勝手に止まるかすると　ここから以下に進む。					  
}

void UtilTimer::Break_Force()
{
	// スレッドを止める
	m_thread1.detach();

	// スレッドの中のループから抜けさせる
	this->m_alive = false;
}

void UtilTimer::Sleep_Milliseconds(long milliseconds)
{
	std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
```

とりあえず　動いている……、よし！

# 2段階目
コメントをもろた。

## UtilTimer.h

DefaultWorkerクラスの OnStep() メソッドんとこを次のように書き換えた。すっきりした。

```C++
/**
 * 指定時間間隔で実行したい処理を書くクラス
 */
class DefaultWorker
{
public:
	DefaultWorker()
	{
		std::cout << "スーパー・クラスのコンストラクターはこれだけど……☆（＾～＾）" << std::endl;
	}

	virtual void OnStep() = 0;
};
```

# 別スレッドでテキスト・ファイルを読込もう

別記事 : 「[C++] テキストファイル読書き (C#プログラマ向け)」 http://qiita.com/muzudho1/items/fa1446b85ae64d01a5ca

参照 : 「std::string の前後の余分な空白文字を取り除く」 (C++ プログラミング) http://program.station.ez-net.jp/special/handbook/cpp/string/trim.asp

これと組み合わせて、別スレッドで　テキスト・ファイルを監視して　存在したら読込むようにしよう。

Worker クラスを、 ReaderWorker に改造する。

Console_Kifuwarabe.cpp

```C++
/**
 * 指定時間間隔で実行したい処理を書くクラス
 *
 * 参照 : 「ファイルやディレクトリの存在確認を行う方法」 (教えて！goo) https://oshiete.goo.ne.jp/qa/3399080.html
 * 参照 : 「FAQ: Cannot convert from 'const char [..]' to 'LPCTSTR'」 (Visual Studio) https://social.msdn.microsoft.com/Forums/vstudio/en-US/c1b08c0a-a803-41c3-ac8c-84eba3be1ddb/faq-cannot-convert-from-const-char-to-lpctstr?forum=vclanguage
 */
class ReaderWorker : public DefaultWorker
{
public:
	ReaderWorker() : DefaultWorker()
	{
		std::cout << "サブクラスのコンストラクター、呼んでるのかだぜ☆（＾～＾）？" << std::endl;
	}

	void OnStep()
	{
		std::string contents;
		if (UtilFile::Read(Kifuwarabe::filename_move, contents)) {
			contents = UtilString::Trim(contents);
			std::cout << "指し手は[" << contents << "]だぜ☆（＾▽＾）ｖ" << std::endl;

		}
		else {
			std::cout << "ファイル[" << Kifuwarabe::filename_move << "]開けね☆（＾～＾）" << std::endl;
		}
	}
};
```

ほんとはここに　局面パーサーとか　書いて　思考ルーチンを叩きたい。

テストは　ほとんど同じ。 main関数で試し書き。

```C++
	// スレッドテスト
	UtilTimer timer;
	ReaderWorker* pWorker1 = new ReaderWorker();
	// スレッドスタート。
	timer.Start(pWorker1, 1000);
	// 10秒経ったら　スレッドを止めよう☆（＾～＾）
	UtilTimer::Sleep_Milliseconds(5000L);
	std::cout << "5秒経ったけど、動いてんの☆（＾～＾）？" << std::endl;
	UtilTimer::Sleep_Milliseconds(5000L);
	timer.Break_Force();
	delete pWorker1;
```

本番では　スレッドを止めずに　結果が出るまで　ずっと動かしておけばいいだろう。