task group에서의 병렬 작업 취소 - 1  에 이은 두 번째 글입니다.


3. 작업이 취소되었을 때 해야 할 것


취소는 그것을 호출했을 때 즉시 동작하지 않습니다. task group이 취소되면 런타임은 각 task interruption point를 발동하여 런타임을 throw 시켜서 활동중인 task가 취소될 때 내부 예외 형을 잡을 수 있습니다. Concurrency Runtime은 런타임이 언제 interruption point를 호출할지 정의되어 있지 않습니다. 런타임이 취소를 할 때 던지는 예외를 잡아서 처리할 필요가 있습니다.

그래서 만약 task의 처리 시간이 긴 경우는 정기적으로 취소 여부를 확인할 필요가 있습니다.

 

< 리스트 4. >

auto t5 = make_task([&] {

   // Perform work in a loop.

   for (int i = 0; i < 1000; ++i)

   {

      // To reduce overhead, occasionally check for

      // cancelation.

      if ((i%100) == 0)

      {

         if (tg2.is_canceling())

         {

            wcout << L"The task was canceled." << endl;

            break;

         }

      }

 

      // TODO: Perform work here.

   }

});

 

<리스트 4>의 굵게 표시한 코드는 task5가 정기적으로 task group tg2가 취소 되었는지 조사하고 있는 것입니다.

 

<리스트 4>는 명시적으로 task5가 속한 task group tg2가 취소되었는지 조사하고 있는데 만약 해당 task가 속한 task group을 직접적으로 호출하지 않고 취소 여부를 조사하고 싶을 때는 is_current_task_group_canceling() 을 사용합니다.

 

 

4. 병렬 알고리즘에서의 취소

 

task group에서 사용하는 병렬 알고리즘도 위에서 소개한 방법으로 취소할 수 있습니다.

 

< 리스트 5. Task group에서 병렬 알고리즘 사용 >

structured_task_group tg;

 

task_group_status status = tg.run_and_wait([&] {

   parallel_for(0, 100, [&](int i) {

      // Cancel the task when i is 50.

      if (i == 50)

      {

         tg.cancel();

      }

      else

      {

         // TODO: Perform work here.

      }

   });

});

 

// Print the task group status.

wcout << L"The task group status is: ";

switch (status)

{

case not_complete:

   wcout << L"not complete." << endl;

   break;

case completed:

   wcout << L"completed." << endl;

   break;

case canceled:

   wcout << L"canceled." << endl;

   break;

default:

   wcout << L"unknown." << endl;

   break;

}

 

<리스트 5> task group tg task를 넣을 때 병렬 알고리즘을 넣었습니다. 그리고 이번 beta2에 새로 생긴 run_and_wait 멤버를 사용하여 task의 실행이 끝날 때 까지 대기하도록 했습니다(예전에는 run 이후에 wait를 호출해야 했습니다).


물론 cancel이 아닌 예외를 발생 시켜서 취소 시킬 수도 있습니다.


< 리스트 6. 병렬 알고리즘에서 예외를 발생시켜서 취소 시키기 >

try

{

   parallel_for(0, 100, [&](int i) {

      // Throw an exception to cancel the task when i is 50.

      if (i == 50)

      {

         throw i;

      }

      else

      {

         // TODO: Perform work here.

      }

   });

}

catch (int n)

{

   wcout << L"Caught " << n << endl;

}

 

<리스트 6>은 하나의 task만 예외를 발생시키고 있기 때문에 task group의 모든 task를 취소

시키기 위해서는 모든 task에서 예외를 발생시켜야 합니다.

그래서 아래의 <리스트 7>과 같이 전역 변수 flag를 사용합니다.

 

< 리스트 7. 모든 병렬 알고리즘의 task 취소 시키기 >

bool canceled = false;

 

parallel_for(0, 100, [&](int i) {

   // For illustration, set the flag to cancel the task when i is 50.

   if (i == 50)

   {

      canceled = true;

   }

 

   // Perform work if the task is not canceled.

   if (!canceled)

   {

      // TODO: Perform work here.

   }

});

 

 


5. Parallel 작업을 취소를 사용하지 못하는 경우

 

취소 작업은 모든 상황에서 다 사용할 수 있는 것은 아닙니다. 특정 시나리오에서는 사용하지 못할 수가 있습니다. 예를 들면 어떤 task는 활동중인 다른 task에 의해 block이 풀렸지만 아직 시작하기 전에 task group이 최소되어 버리면 계속 시작하지 못하여 결과적으로 애플리케이션이 dead lock 상황에 빠지게 됩니다.




이것으로 task group에서의 병렬 작업의 취소에 대한 것은 마칩니다. 다음에는 Beta2에 드디어 구현된 Concurrency Container에 대해서 설명하겠숩니다.


참고 url
MSDN : http://msdn.microsoft.com/en-us/library/dd984117(VS.100).aspx