Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

C++ Concurrency in Action 9-2 Interrupting threads

915 Aufrufe

Veröffentlicht am

C++ Korea
C++ Concurrency in Action
Study
Chapter 09 Advanced thread management
9.2 Interrupting threads

Veröffentlicht in: Software
  • Loggen Sie sich ein, um Kommentare anzuzeigen.

C++ Concurrency in Action 9-2 Interrupting threads

  1. 1. C++ Concurrency in Action Study C++ Korea Chapter 09 Advanced thread management 9.2 Interrupting threads C++ Korea C++ Concurrency in Action Study C++ Korea 박 동하 (luncliff@gmail.com) C++ Korea 윤석준 (seokjoon.yun@gmail.com)
  2. 2. C++ Concurrency in Action Study C++ Korea Interrupting Thread • long-running thread를 정지시킬 때 • 동작중인 thread가 아닌 다른 thread에서 작업을 중지시키고 싶을 때 • 특히 사용자가 명시적으로 [작업 취소]를 누른 경우 • GUI (특히 MFC)에서는 Signal (Message)로 처리 • C++11에서는 interrupting thread를 제공해주지 않지만, 쉽게 구현이 가능함 • 기존 thread에 interrupt거는 함수와 interrupt되는 함수 구현이면 끝! interrupt( ) interrupt_point( ) 2
  3. 3. C++ Concurrency in Action Study C++ Korea Basic Implementation of interruptible_thread Simple하게 while-loop 안에서interrupt check
  4. 4. C++ Concurrency in Action Study C++ Korea interruptible_thread 4 class interruptible_thread { std::thread internal_thread; interrupt_flag* flag; public: template<typename FunctionType> interruptible_thread(FunctionType f) { std::promise<interrupt_flag*> p; internal_thread = std::thread([f, &p] { p.set_value(&this_thread_interrupt_flag); f(); }); flag = p.get_future().get(); } void interrupt() { if (flag) flag->set(); } void join() { internal_thread.join(); } void detach() { internal_thread.detach(); } bool joinable() const { return internal_thread.joinable(); } }; std::thread 기능 interrupt 거는 기능 생성자 : 함수 실행
  5. 5. C++ Concurrency in Action Study C++ Korea interrupt_flag 5 class interrupt_flag { std::atomic<bool> flag; public: void set() { flag.store(true, std::memory_order_relaxed); } bool is_set() const { return flag.load(std::memory_order_relaxed); } }; thread_local interrupt_flag this_thread_interrupt_flag; void interruption_point() { if (this_thread_interrupt_flag.is_set()) throw thread_interrupted(); } interrupt 거는 기능 각 thread별로 flag를 가짐 interrupt flag
  6. 6. C++ Concurrency in Action Study C++ Korea6 Basic Implementation of interruptible_thread DEMO !!!
  7. 7. C++ Concurrency in Action Study C++ Korea DEMO 결과는 ??? 7 • 잘 동작함 • 별 문제 없어 보임 • 근데 왜 ??? 작가는 ??? • while-loop에서 interrupt를blocking으로 기다리는 게마음에안 드는듯;;; • 그래서 ? • std::condition_variable을 이용하여 interruptible_wait()를 구현 • 추가로 std::mutex와 std::lock_guard<>도 같이 사용을… ;;; • 하지만program 구조상while-loop를 사용하는 경우는이예제가최고의 solution이지 않을까라는 의견을 살포시조심스럽고 소심하게 제시해봄
  8. 8. C++ Concurrency in Action Study C++ Korea A Broken version of interruptible_wait for std::condition_variable std::condition_variable::wait()로 대기 but, 깨우는데 쌩까고계속잘 수있음 ;;;
  9. 9. C++ Concurrency in Action Study C++ Korea interruptible_wait (추가) 9 if set then throw exception void interruptible_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { interruption_point(); this_thread_interrupt_flag.set_condition_variable(cv); cv.wait(lk); this_thread_interrupt_flag.clear_condition_variable(); interruption_point(); } throw exception
  10. 10. C++ Concurrency in Action Study C++ Korea interrupt_flag (수정) std::condition_variable* 추가 보호할 목적의 std::mutex 추가 class interrupt_flag { std::atomic<bool> flag; std::condition_variable* thread_cond; std::mutex set_clear_mutex; public: interrupt_flag() : thread_cond(0) {} void set() { flag.store(true, std::memory_order_relaxed); std::lock_guard<std::mutex> lk(set_clear_mutex); if (thread_cond) thread_cond->notify_all(); } bool is_set() const { return flag.load(std::memory_order_relaxed); } void set_condition_variable(std::condition_variable& cv) { std::lock_guard<std::mutex> lk(set_clear_mutex); thread_cond = &cv; } void clear_condition_variable() { std::lock_guard<std::mutex> lk(set_clear_mutex); thread_cond = 0; } }; set() 에 std::condition_variable::notify_all( ) 추가 std::condition_variable이 설정되지 않아도 정상동작 std::condition_variable set() , clear() 함수 추가
  11. 11. C++ Concurrency in Action Study C++ Korea A Broken version of interruptible_wait for std::condition_variable DEMO !!!
  12. 12. C++ Concurrency in Action Study C++ Korea DEMO 결과는 ??? 12 • 잘 동작함 • 별 문제 없어 보임 • 앞서 본 while-loop 형식도 여기서 잘 동작함 • 근데 ???? void interruptible_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { interruption_point(); this_thread_interrupt_flag.set_condition_variable(cv); cv.wait(lk); this_thread_interrupt_flag.clear_condition_variable(); interruption_point(); } 이 사이에 interrupt가 발생한 경우 ???
  13. 13. C++ Concurrency in Action Study C++ Korea A Broken version of interruptible_wait for std::condition_variable DEMO !!! #2
  14. 14. C++ Concurrency in Action Study C++ Korea DEMO 결과는 ??? 14 • interrupt 씹혔음 ;;;; • 다시 보내니깐 정상적으로 interrupt 됨 • 그럼 대안은 ???? • 그 사이를 다른 std::mutex로 보호 ? • 서로의 수명을 모르는 thread 들끼리 mutex 참조를 통과 -> 위험함 • wait() 대신 wait_for()를 사용하여 대기 시간의 제한을 둠 • spurious wake (가짜 깸)이 자주 일어나겠지만 해결 됨
  15. 15. C++ Concurrency in Action Study C++ Korea Using timeout in interruptible_wait for std::condition_variable 깨우는거쌩까지는 않는데… while-loop 안에서wait_for( )로 check
  16. 16. C++ Concurrency in Action Study C++ Korea clear_cv_on_destruct (추가) 16 std::condition_variable의clear()를 RAII로 관리 struct clear_cv_on_destruct { ~clear_cv_on_destruct() { this_thread_interrupt_flag.clear_condition_variable(); } };
  17. 17. C++ Concurrency in Action Study C++ Korea interruptible_wait (수정) 17 void interruptible_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { interruption_point(); this_thread_interrupt_flag.set_condition_variable(cv); clear_cv_on_destruct guard; interruption_point(); cv.wait_for(lk, std::chrono::milliseconds(1)); interruption_point(); } when cv set and throw exception without cv clear, then cv clear automatically
  18. 18. C++ Concurrency in Action Study C++ Korea interruptible_wait using predicate (추가) 18 template<typename Predicate> void interruptible_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk, Predicate pred) { interruption_point(); this_thread_interrupt_flag.set_condition_variable(cv); interrupt_flag::clear_cv_on_destruct guard; while (!thie_thread_interrupt_flag.is_set() && !pred()) { cv.wait_for(lk, std::chrono::milliseconds(1)); } interruption_point(); }
  19. 19. C++ Concurrency in Action Study C++ Korea Using timeout in interruptible_wait for std::condition_variable DEMO !!!
  20. 20. C++ Concurrency in Action Study C++ Korea DEMO 결과는 ??? 20 • 잘 동작함 • 무슨 수를 써도 무조건 잘 동작함 • 근데 std::condition_variable 말고 std::condition_variable_any를쓸려면 ??? (그냥std::unique_lock<std::mutex>만 쓰면될껄…. 또뭘더쓸려고… 참…)
  21. 21. C++ Concurrency in Action Study C++ Korea interruptible_wait for std::condition_variable_any std::condition_variable_any를 작가님이굳이쓰시겠다는데 머… 다시while-loop 없이 wait( )로 대기
  22. 22. C++ Concurrency in Action Study C++ Korea interrupt_flag에 std::condition_variable_any 추가 22 class interrupt_flag { std::atomic<bool> flag; std::condition_variable* thread_cond; std::condition_variable_any* thread_cond_any; std::mutex set_clear_mutex; public: interrupt_flag() : thread_cond(0) , thread_cond_any(0) {} void set() { flag.store(true, std::memory_order_relaxed); std::lock_guard<std::mutex> lk(set_clear_mutex); if (thread_cond) thread_cond->notify_all(); else if (thread_cond_any) thread_cond_any->notify_all(); } std::condition_variable_any* 추가 std::condition_variable_any의 notify_all() 추가
  23. 23. C++ Concurrency in Action Study C++ Korea interrupt_flag에 wait( ) (추가) 23 template<typename Lockable> void interrupt_flag::wait(std::condition_variable_any& cv, Lockable& lk) { struct custom_lock { … }; custom_lock cl(this, cv, lk); interruption_point(); cv.wait(cl); interruption_point(); } struct custom_lock { interrupt_flag* self; Lockable& lk; custom_lock(interrupt_flag* self_, std::condition_variable_any& cond, Lockable& lk_) : self(self_) , lk(lk_) { self->set_clear_mutex.lock(); self->thread_cond_any = &cond; } void unlock() { lk.unlock(); self->set_clear_mutex.unlock(); } void lock() { std::lock(self->set_clear_mutex, lk); } ~custom_lock() { self->thread_cond_any = 0; self->set_clear_mutex.unlock(); } }; lock unlock exception이 발생하여도 무조건 unlock template<typename Lockable> void interruptible_wait(std::condition_variable_any& cv, Lockable& lk) { this_thread_interrupt_flag.wait(cv, lk); }
  24. 24. C++ Concurrency in Action Study C++ Korea interruptible_wait for std::condition_variable_any DEMO !!!
  25. 25. C++ Concurrency in Action Study C++ Korea DEMO 결과는 ??? 25 • 잘 동작함 • 뚤어보려 애썼는데… 안뚤림 ;;; • 작가님이 한가지만 더 살펴보자는데… std::future 같이 다른 blocking call에 interrupt를 주려면 ???
  26. 26. C++ Concurrency in Action Study C++ Korea interrupting other blocking calls
  27. 27. C++ Concurrency in Action Study C++ Korea interruptible_wait( ) using std::future 27 interrupt가 걸려도 빠져나가고 template<typename T> void interruptible_wait(std::future<T>& uf) { while (!this_thread_interrupt_flag.is_set()) { if (uf.wait_for(lk, std::future_status::ready == std::chrono::milliseconds(1))) break; } } 작업이 끝나도 빠져나가고 주기적으로 check
  28. 28. C++ Concurrency in Action Study C++ Korea interrupting other blocking calls DEMO ??? Pass !!! 고마보자. 많이봤다. 아이가;;;
  29. 29. C++ Concurrency in Action Study C++ Korea Handling interrupt 그동안 DEMO에서많이봤는데… 맹그거임.
  30. 30. C++ Concurrency in Action Study C++ Korea Handling interrupt 30 딱히 설명이 필요할지… try { do_something(); } catch (thread_interrupted&) { handle_interrupt(); }
  31. 31. C++ Concurrency in Action Study C++ Korea Handling interrupt 31 딱히 설명이 필요할지… try { do_something(); } catch (thread_interrupted&) { handle_interrupt(); } - 그런데, 이렇게 외부에서 exception을 처리 하는 경우, 만약 실수로 처리를 안하게 되면 ? std::terminate()가 호출되어 program이 종료 될 수도 있다. - 왠만하면 thread 내부에서 exception을 처리해 주는게 안전하다.
  32. 32. C++ Concurrency in Action Study C++ Korea Handling interrupt in internal_thread constructor 32 아에 internal_thread 생성시 함수 실행 부분에서 exception 처리를 했다. template<typename FunctionType> interruptible_thread(FunctionType f) { std::promise<interrupt_flag*> p; internal_thread = std::thread([f, &p] { p.set_value(&this_thread_interrupt_flag); try { f(); } catch (thread_interrupted const&) { handle_interrupt(); } }); flag = p.get_future().get(); }
  33. 33. C++ Concurrency in Action Study C++ Korea Summary 33 • 여러가지 방법으로 thread를 interrupt하는 방법을 살펴 봄. • while-loop 안에서 interruption_point( ) 체크 • std::condition_variable, std::condition_variable_any를 이용 • 다른 blocking 방법에 대한 예제 (std::future)
  34. 34. C++ Concurrency in Action Study C++ Korea Q & A

×