프로그래밍/Parallel Programming

병렬 프로그래밍 Parallel Programming - cancellation_token

nanze 2022. 1. 3. 21:57
반응형

이전 정리글은

2022.01.03 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - concurrent_unordered_map

 

병렬 프로그래밍 Parallel Programming - concurrent_unordered_map

이전 정리글은 2021.12.30 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - concurrent_vector 자 오늘은 일곱번째 정리시간이다. 호랑이해 들어 첫 포스팅이다. 이번 해에는 호랑..

nanze.tistory.com

 

지난 포스팅에 이어 ppl 에서 제공하는 task 들을 취소할 수 있는 방법을 알아보자.  개발 공부를 처음 접하거나 초창기에는 전역 변수 등을 두고 해당 변수를 루프 안에서 보는 보통 그런식으로 하거나 아니면 좀 더 나아가면 이벤트 방식을 사용하거나 모 다양할 것인데 ppl task를 캔슬하기 위해서는 ppl 에서 다음과 같은 방식을 지원한다. 

concurrency::cancellation_token_source

위 클래스를 사용하면 각 task 생성 시 토큰을 등록하고 토큰을 등록한 task 들은 cancellation_token_source 를 이용하여 취소 요청을 할 수 있다. 코드를 보자. :) 

#include <ppl.h>
#include <ppltasks.h>
#include <iostream>

using namespace std;

bool func()
{
    wcout << L"func() now running.. " << endl;
    concurrency::wait(1000);
    return true;
}

int main()
{
    concurrency::cancellation_token_source cancelToken;
    concurrency::cancellation_token token = cancelToken.get_token();
    
    auto task = concurrency::create_task( [&]
        {
            while(true){
                if( token.is_canceled())
                {
                    concurrency::cancel_current_task();
                }else{
                    func();
                }
            }
        }
    , token);
    concurrency::wait(100);
    wcout << L"canceling task...." << endl;
    cancelToken.cancel();
    
    concurrency::task_status st = task.wait();
    
    switch(st){
        case concurrency::task_status::canceled :
        wcout << L"Task canceled." << endl;
        break;
        case  concurrency::task_status::completed :
        wcout << L"Task completed." << endl;
        break;
    }

    return 0;
}

위 코드를 보면 cancellation_token_source 를 통해 token 을 생성하고 해당 token 을 task 생성 시 인자로 전달하고 있다. 해당 task 는 해당 token 을 통하여 취소 요청을 확인할 수 있는 것이다. token 의 취소 요청은 cancellation_token 의 is_canceled 함수를 통하여 알 수 있다. 해당 통지를 받으면 task는 cancel_current_task 를 통하여 현재 task 를 취소할 수 있다. 

 

다음은 다른 코드를 보자. 

#include <ppl.h>
#include <ppltasks.h>
#include <iostream>

using namespace std;

bool func()
{
    wcout << L"func() now running.. " << endl;
    concurrency::wait(1000);
    return true;
}

int main()
{
    concurrency::cancellation_token_source cancelToken;
    concurrency::cancellation_token token = cancelToken.get_token();
    
    concurrency::event evt;
    concurrency::cancellation_token_registration reg;
    
    reg = token.register_callback([&evt, &token, &reg]() {
		    wcout << L"callback is called." << endl;
			evt.set();
			token.deregister_callback(reg);
	    }
	);
    
    auto task = concurrency::create_task( [&]
        {
            while(true){
                if( token.is_canceled())
                {
                    concurrency::cancel_current_task();
                }else{
                    func();
                }
            }
        }
    , token);
    concurrency::wait(100);
    wcout << L"canceling task...." << endl;
    cancelToken.cancel();
    
    concurrency::task_status st = task.wait();
    
    switch(st){
        case concurrency::task_status::canceled :
        wcout << L"Task canceled." << endl;
        break;
        case  concurrency::task_status::completed :
        wcout << L"Task completed." << endl;
        break;
    }
    
    evt.wait();
    
    return 0;
}

위 코드는 이전 코드와 유사하고 한가지 추가된 것이다. 그것은 token의 cancel 이 발생하였을 경우 callback 함수를 등록하여 해당 함수가 실행될 수 있도록 한 것이다. task 의 작업 취소가 발생하였을 경우 반드시 일어나야 할 리소스 해제나 다른 프로세스가 있을 경우 사용하면 유용할 것 같다. 

 

다음은 task group 에 대한 취소에 대해서 알아보자.

#include <ppl.h>
#include <ppltasks.h>
#include <iostream>

using namespace std;

bool func()
{
	wcout << L"func() now running.. " << endl;
	concurrency::wait(1000);
	return true;
}

int main()
{
	concurrency::cancellation_token_source cancelToken;
	concurrency::cancellation_token token = cancelToken.get_token();

	concurrency::structured_task_group stg(token);

	auto task = concurrency::make_task([&]
	{
		while (true) {
			//if (token.is_canceled())
			if(concurrency::is_current_task_group_canceling())
			{
				//concurrency::cancel_current_task();
				break;
			}
			else {
				func();
			}
		}
	}
	);
	stg.run(task);
	concurrency::wait(100);
	wcout << L"canceling group task...." << endl;
	cancelToken.cancel();
	concurrency::task_group_status st = stg.wait();
	//concurrency::task_status st = task.wait();

	switch (st) {
	case concurrency::task_group_status::canceled:
		wcout << L"Task Group canceled." << endl;
		break;
	case  concurrency::task_group_status::completed:
		wcout << L"Task Group completed." << endl;
		break;
	}

	return 0;
}

위의 코드는 structed_task_group 에 대하여 취소를 수행하고 있다. 일반적인 task 와 다른 점은 취소 판단을 하기위해 is_current_task_group_canceling 를 사용하는 것과 취소 판단 시 break 를 통해 종료하는 것이다. 그 외에는 일반적인 task 의 취소 루틴과 동일하다고 볼 수 있다. 

 

다음 정리는 

2022.01.05 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - cancellation_token 특성

 

병렬 프로그래밍 Parallel Programming - cancellation_token 특성

이전 정리글 2022.01.03 - [프로그래밍/Parallel Programming] - 병렬 프로그래밍 Parallel Programming - cancellation_token 병렬 프로그래밍 Parallel Programming - cancellation_token 이전 정리글은 2022.01..

nanze.tistory.com

 

 

 

 

 

 

 

반응형