2014-11-19 4 views
1

У увеличения потока есть удобная функция «прерывания». Рамка вводит точки прерывания во время сна и т. Д. Однако использование блокировки вызовов Win32 обойти эту функцию. Например, WaitForSingleObject будет блокировать поток, но не будет препятствовать его прерыванию механизмом прерывания потока.Использование WaitForSingleObject в Windows, но поддержка прерываний прерывания потока

Есть ли способ обернуть WaitForSingleObject или сказать boost, чтобы ждать на дескрипторе события Win32, чтобы я мог восстановить точку прерывания?

+0

Вы должны быть откровенными и сказать, что ваш поток безопасен для прерывания. Для этого требуется WaitForSingleObjectEx() с аргументом bAlertable, установленным в TRUE. Не делайте обещаний, которые вы не можете сохранить. –

ответ

2

detail::win32::interruptible_wait реализует именно это.

Как вы можете видеть, он ждет 3 ручек (2 в дополнение к указанному вызывающим абонентом), чтобы соблюдать прерывание.

См специфически

  • WaitForMultipleObjectsEx вызова
  • блок

    else if(notified_index==interruption_index) 
    { 
        detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); 
        throw thread_interrupted(); 
    } 
    

Для справки, Boost License:

bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time) 
{ 
    detail::win32::handle handles[3]={0}; 
    unsigned handle_count=0; 
    unsigned wait_handle_index=~0U; 
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 
    unsigned interruption_index=~0U; 
#endif 
    unsigned timeout_index=~0U; 
    if(handle_to_wait_for!=detail::win32::invalid_handle_value) 
    { 
     wait_handle_index=handle_count; 
     handles[handle_count++]=handle_to_wait_for; 
    } 
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 
    if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled) 
    { 
     interruption_index=handle_count; 
     handles[handle_count++]=detail::get_current_thread_data()->interruption_handle; 
    } 
#endif 
    detail::win32::handle_manager timer_handle; 

#ifndef UNDER_CE 
#if !BOOST_PLAT_WINDOWS_RUNTIME 
    unsigned const min_timer_wait_period=20; 

    if(!target_time.is_sentinel()) 
    { 
     detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds(); 
     if(time_left.milliseconds > min_timer_wait_period) 
     { 
      // for a long-enough timeout, use a waitable timer (which tracks clock changes) 
      timer_handle=CreateWaitableTimer(NULL,false,NULL); 
      if(timer_handle!=0) 
      { 
       LARGE_INTEGER due_time=get_due_time(target_time); 

       bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0; 
       if(set_time_succeeded) 
       { 
        timeout_index=handle_count; 
        handles[handle_count++]=timer_handle; 
       } 
      } 
     } 
     else if(!target_time.relative) 
     { 
      // convert short absolute-time timeouts into relative ones, so we don't race against clock changes 
      target_time=detail::timeout(time_left.milliseconds); 
     } 
    } 
#endif 
#endif 

    bool const using_timer=timeout_index!=~0u; 
    detail::timeout::remaining_time time_left(0); 

    do 
    { 
     if(!using_timer) 
     { 
      time_left=target_time.remaining_milliseconds(); 
     } 

     if(handle_count) 
     { 
      unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0); 
      if(notified_index<handle_count) 
      { 
       if(notified_index==wait_handle_index) 
       { 
        return true; 
       } 
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 
       else if(notified_index==interruption_index) 
       { 
        detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); 
        throw thread_interrupted(); 
       } 
#endif 
       else if(notified_index==timeout_index) 
       { 
        return false; 
       } 
      } 
     } 
     else 
     { 
      detail::win32::sleep(time_left.milliseconds); 
     } 
     if(target_time.relative) 
     { 
      target_time.milliseconds-=detail::timeout::max_non_infinite_wait; 
     } 
    } 
    while(time_left.more); 
    return false; 
}