プログラマーの卵の日記

備忘録になってます!小難しそうなことから超簡単なことまでやってます!!

【C++】Threadについて分かった気になってみる

構成


No.1 補足
No.2 std::thread
No.3 std::mutex







      No.1 補足


 先に伝えますが、理解しているようで理解できていないと思うので読むならそのつもりで見てください。


では、何故その状態で記事を書こうと思ったかというと、DxLibというライブラリにてロード画面のための非同期処理を自作するべく、Threadについて勉強しつつMutexについても勉強しつつtry-catchについても勉強していました。


ですが、何度、やっても、上手くいかず、心が、折れたので、やめました。
勿体ないので今勉強していた知識だけでもまとめてThread君とは時間と距離を置こうと思います。

最後に心の折れたコードだけでも上げます。





      No.2 std::thread


ぶっちゃけここ見ろ定期→std::thread

std::threadを作成したタイミングで新しくスレッドが作成されます。


作成する方法としてはいくつかあります。状態に応じたものでいくつかコードを示します。

色んなサイト見てたら色んな記述あったので見つけたものだけでも全部載せます。パターンが多いので長くなりますが、めんどくさくなったのでいくつか端折ってます。

 


・スレッドに処理内容与える


	int x = 0;
	std::thread t;
	t = std::thread([&]
		{
			++x;
		}
	);

 


	int x = 0;
	std::thread t;
	t = std::thread([&x]
		{
			++x;
		}
	);

 


	int x = 0, y = 0;
	std::thread t;
	t = std::thread([&]
		{
			++x;
			y = 10;
		}
	);

 


	int x = 0, y = 0;
	std::thread t;
	t = std::thread([&x, &y]
		{
			++x;
			y = 10;
		}
	);



・スレッドに返り値も引数も無い関数を与える


int x = 0, y = 0;
void Process()
{
	x = 10;
	y = 20;
}
int main()
{
	std::thread t;
	t = std::thread(Process);

 


int x = 0, y = 0;
void Process()
{
	x = 10;
	y = 20;
}
int main()
{
	std::thread t;
	t = std::thread(&Process);

 


int x = 0, y = 0;
void Process()
{
	x = 10;
	y = 20;
}
int main()
{
	std::thread t;
	t = std::thread([]
		{
			Process();
		}
	);



・スレッドに返り値のある関数を与える


int x = 0, y = 0;
bool Process()
{
	x = 10;
	y = 20;

	return true;
}
int main()
{
	bool end = false;
	std::thread t;
	t = std::thread([&]
		{
			end = Process();
		}
	);



・スレッドに戻り値のある関数を与える


void Process(int x, int y)
{
	std::cout << x << "\t" << y << std::endl;
}
int main()
{
	int x = 6;
	int y = 10;
	std::thread t;
	t = std::thread(Process, x, y);

 


void Process(int x, int y)
{
	std::cout << x << "\t" << y << std::endl;
}
int main()
{
	int x = 6;
	int y = 10;
	std::thread t;
	t = std::thread(&Process, x, y);

 


void Process(int x, int& y)
{
	y = x + y;
	std::cout << x << "\t" << y << std::endl;
}
int main()
{
	int x = 6;
	int y = 10;
	std::thread t;
	t = std::thread(Process, x, std::ref(y));

 


void Process(int x, int& y)
{
	y = x + y;
	std::cout << x << "\t" << y << std::endl;
}
int main()
{
	int x = 6;
	int y = 10;
	std::thread t;
	t = std::thread(&Process, x, std::ref(y));



・スレッドにメンバ関数を与える


class A
{
private:
	std::thread th;
	int x;
	int y;

public:
	A() :x(15), y(25) 
	{
		th = std::thread(&A::Process, this);
	}
	~A() 
	{
		th.join();
	}

	void Process()
	{
		std::cout << x << "\t" << y << std::endl;
	}
};
int main()
{
	A a;

 


class A
{
private:
	std::thread th;

public:
	A(int x, int y) 
	{
		th = std::thread(&A::Process, this, x, y);
	}
	~A() 
	{
		th.join();
	}

	void Process(int x, int y)
	{
		std::cout << x << "\t" << y << std::endl;
	}
};
int main()
{
	int y = 10;
	A a(5, y);



これがスレッドを作成する方法です。


std::thread th;の時点では新しいスレッドを作られません。th = std::thread(...を記述した瞬間動き出します。


では、これをほっといて良いのかといえばそんなことはなく、終了させる処理が必要です。といっても簡単です。


join(); もしくは detach();を呼ばなければなりません。両方とも同じようなものですが違う部分があります。
join はスレッドの処理終わってなければ終了するまでブロックするものです。detach はスレッドの処理が終えてなかろうが関係なくスレッドを破棄します。

正直言葉だとよくわからなかったので実行して見れば、joinが呼ばれたらそのスレッドの処理が終わるまで同期とかメインスレッドは止まります。

例えばforループ内にスレッド作成とjoinを同時に行えば全てのスレッドが終わるまでループを抜け出せません。
また、join とdetachが呼ばれたらスレッドは空のオブジェクトになるのでもう一度joinまたはdetachを呼べばエラーで終了されます。


それでスレッドについて注意してほしい点としては、スレッドの個数はパソコンの性能によって制限されます。
で、その数はこれで分かります。


    std::thread::hardware_concurrency()






      No.3 std::mutex


mutexについては正直よくわかっていないです。
Javaをやっていた時にデッドロックについて学習しているのでその類だとは思っているのですが、、、使い方がよくわからない。。。。。

詳細はここを見れば大抵わかると思います。
で、いろんなサイトを辿ったら、たぶんおそらくこれを呼べばいいんだろうなとは思ってます。


    std::mutex mtx_;
    std::lock_guard lock(mtx_);







 もっと勉強して理解深めたらまた書きます。try-catchについては書けるほどの知識ないのでやめときます。