C++ 在Windows上使用WaitForSingleObject但支持boost线程中断

C++ 在Windows上使用WaitForSingleObject但支持boost线程中断,c++,windows,boost,boost-thread,interrupt-handling,C++,Windows,Boost,Boost Thread,Interrupt Handling,Boost线程具有方便的“可中断”特性。该框架在睡眠等情况下引入了中断点。但是,使用阻止Win32调用可以绕过此功能。例如,WaitForSingleObject将阻止一个线程,但不会让它被boost线程的中断机制中断 有没有办法包装WaitForSingleObject或告诉boost等待Win32事件句柄,这样我就可以重新获得中断点?详细信息::Win32::Interruptable_wait实现了这一点 正如您所看到的,它等待3个句柄(除了调用方指定的句柄之外还有2个)来接受中断 具体见

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


有没有办法包装WaitForSingleObject或告诉boost等待Win32事件句柄,这样我就可以重新获得中断点?

详细信息::Win32::Interruptable_wait
实现了这一点

正如您所看到的,它等待3个句柄(除了调用方指定的句柄之外还有2个)来接受中断

具体见

  • WaitForMultipleObjectsEx
    调用
  • 街区

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

bool可中断的等待(细节::win32::句柄到等待,细节::超时目标时间)
{
细节::win32::句柄句柄[3]={0};
无符号句柄计数=0;
无符号等待句柄索引=~0U;
#如果定义了BOOST\u,线程\u会提供\u中断
无符号中断指数=~0U;
#恩迪夫
无符号超时\u索引=~0U;
if(handle\u to\u wait\u for!=详细信息::win32::无效的\u handle\u值)
{
等待句柄索引=句柄计数;
handles[handle_count++]=handle_to_wait_等待;
}
#如果定义了BOOST\u,线程\u会提供\u中断
if(细节::获取当前线程数据()&&detail::获取当前线程数据()->已启用中断)
{
中断指数=句柄计数;
handles[handle\u count++]=detail::获取当前线程数据()->中断句柄;
}
#恩迪夫
详细信息::win32::句柄\u管理器计时器\u句柄;
#ifndef下
#如果!BOOST\u平台\u WINDOWS\u运行时
无符号常量最小计时器等待周期=20;
如果(!target_time.is_sentinel())
{
详细信息::超时::剩余时间常量时间左=目标时间。剩余毫秒();
if(time\u left.millides>min\u timer\u wait\u period)
{
//对于足够长的超时时间,使用可等待计时器(跟踪时钟变化)
timer_handle=CreateWaitableTimer(NULL、false、NULL);
如果(计时器句柄!=0)
{
大整数到期时间=获取到期时间(目标时间);
bool const set_time_successed=SetWaitableTimer(计时器句柄和到期时间,0,0,0,false)!=0;
如果(设置时间成功)
{
超时\索引=句柄\计数;
句柄[handle_count++]=计时器句柄;
}
}
}
否则如果(!target_time.relative)
{
//将较短的绝对超时转换为相对超时,这样我们就不会与时钟变化竞争
target\u time=detail::timeout(time\u left.毫秒);
}
}
#恩迪夫
#恩迪夫
使用计时器的布尔常量=超时索引!=~0u;
详细信息::超时::剩余时间剩余时间(0);
做
{
如果(!使用_计时器)
{
time_left=目标时间。剩余的_毫秒();
}
如果(句柄计数)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(句柄计数,句柄,false,使用计时器?无限:time_left.毫秒,0);
如果(通知中断处理);
抛出线程_中断();
}
#恩迪夫
else if(通知的索引==超时索引)
{
返回false;
}
}
}
其他的
{
详细信息::win32::睡眠(剩余时间为毫秒);
}
if(目标时间相对)
{
目标时间。毫秒-=细节::超时::最大非无限等待;
}
}
而(剩下的时间,更多);
返回false;
}

您必须明确表示您的线程可以安全地被中断。这需要将bAlertable参数设置为TRUE的WaitForSingleObjectEx()。不要许下你无法兑现的诺言。
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;
}