在 Windows 上使用 WaitForSingleObject 但支持提升线程中断

Posted

技术标签:

【中文标题】在 Windows 上使用 WaitForSingleObject 但支持提升线程中断【英文标题】:Using WaitForSingleObject on Windows but supporting boost thread interrupts 【发布时间】:2014-11-19 20:41:30 【问题描述】:

Boost 线程具有“可中断”的便利特性。该框架在您睡眠等时引入了中断点。但是,使用阻塞 Win32 调用可以绕过此功能。比如WaitForSingleObject会阻塞一个线程,但不会让它被boost线程的中断机制打断。

有什么方法可以包装 WaitForSingleObject 或告诉 boost 等待 Win32 事件句柄,以便我可以重新获得中断点?

【问题讨论】:

您必须明确表示您的线程可以安全地被中断。这需要将 bAlertable 参数设置为 TRUE 的 WaitForSingleObjectEx()。不要做出无法兑现的承诺。 【参考方案1】:

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;

【讨论】:

以上是关于在 Windows 上使用 WaitForSingleObject 但支持提升线程中断的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 上使用长双打

在 Windows 10 上使用 VS Code 在 iphone 上调试颤振

如何使用WINE在Linux上使用Windows .lib

使用子进程在 Windows 上运行 Python 脚本

在 Linux 上使用此 .htaccess 获取错误 500,在 Windows 上运行良好

在 Octave 上使用 libsvm (Windows)