Server/C++

Future와 Asynchronous

Juzdalua 2024. 7. 30. 19:09

하나의 작은 함수를 비동기 방식을 활용할 때 사용한다.

스레드를 따로 만들지 않아도, 자동으로 멀티스레드 환경을 제공한다.

스레드 관리가 필요 없으므로 로딩 등 가벼운 방식에서 사용하면 효율적이다.

 

mutex, condition_variable까지 가지 않고 일회성으로 처리할 수 있는 단순한 것들을 처리할 때 용이하다.

 

비동기와 멀티스레드는 같은 개념이 아니다.

비동기 호출이 된다면 멀티스레드로 호출이 될 수 있다. (luanch::async)


Future

원하는 함수를 비동기적으로 실행한다.

#include <future>

/*
	1. launch::deferred -> lazy evaluation 지연해서 실행-> 순서만 뒤로 미룬다
	2. launch::async -> 별도의 스레드를 만들어서 병렬로 실행 -> 멀티스레드 활용
	3. launch::deferred | async -> 둘 중 알아서 골라서 진행
*/

// 커맨드 패턴
future<int64> future = async(launch::async, 함수명);

future_status status = future.wait_for(1ms); // 생략 가능
if (status == future_status::ready) {
	int64 sum = future.get();
}

 

future 비동기 멀티스레드 방식 사용방법

#include "pch.h"
#include "CorePch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <future>

int64 Calculate() {
	int64 sum = 0;
	for (int32 i = 0; i < 1'000'000; i++) {
		sum += i;
	}
	return sum;
}

int main()
{
	// 비동기 수행
    future<int64> future = async(launch::async, Calculate);

    future_status status = future.wait_for(1ms); // 생략 가능
    if (status == future_status::ready) {
        int64 sum = future.get();
    }	
}

 

멤버함수 호출시 사용방법

class Knight {
public:
    int64 GetHP() { return 100; }
};
Knight knight;
std::future<int64> future2 = async(launch::async, &Knight::GetHP, knight); // knight.GetHP()

Promise

결과물을 promise를 통해 future로 받아온다.

 

std::promise와 std::future

#include "pch.h"
#include "CorePch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <future>

void PromiseWorker(std::promise<string>&& promise) {
	promise.set_value("Secret Message");
}

int main()
{
	// std::promise
	// 미래(std::promise)에 결과물을 반환해줄거라 약속(std::promise)
	std::promise<string> promise;
	std:future<string> future = promise.get_future();

	// t 스레드에게 PromiseWorker 함수 소유권을 넘겨준다.
	thread t(PromiseWorker, std::move(promise));

	string message = future.get(); //future.get() 함수가 호출되면 future 객체는 empty상태로 돌아간다.
	cout << message << endl;
	t.join();
}

Packaged_task

원하는 함수의 실행 결과를 packaged_task를 통해 future로 받아온다.

 

std::packaged_task

#include "pch.h"
#include "CorePch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <future>

int64 Calculate() {
	int64 sum = 0;
	for (int32 i = 0; i < 1'000'000; i++) {
		sum += i;
	}
	return sum;
}

void TaskWorker(std::packaged_task<int64(void)>&& task) {
	task();
}

int main()
{

	// packaged_task<함수 리턴타입(함수 매개변수 타입)>
	std::packaged_task<int64(void)> task(Calculate);
	std::future<int64> future = task.get_future();
	/*
		매개변수로 들어간 Calculate 함수의 결과값을 future객체가 받아올 수 있다.
	*/

	thread t(TaskWorker, std::move(task));
	int sum = future.get();
	cout << sum << endl;


}