📄 taskcollectionbase.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// TaskCollectionBase.cpp
//
// General abstract collection of work counting / eventing implementation
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
namespace details
{
/// <summary>
/// Called when an exception is raised on a chore on a given task collection, this makes a determination of what to do with the exception
/// and stores it for potential transport back to the thread performing a join on a task collection.
/// </summary>
void _TaskCollectionBase::_RaisedException()
{
//
// Current strategy is that the first exception in is kept and rethrown. We may update this in the future.
//
void * _OldStatus = _M_pException;
for (;;)
{
//
// We always overwrite the cancel exception being here. Everything else is "more important".
//
std::exception_ptr *_pException = (std::exception_ptr *)((size_t)_OldStatus & ~_S_cancelBitsMask);
if (_pException != NULL && (size_t)_pException != _S_cancelException)
return;
//
// Maintain the lower bit as a cancel status flag to determine where to stop a cancellation.
//
size_t _cancelStatus = ((size_t)_OldStatus & _S_cancelBitsMask);
void * _XchgStatus = _InterlockedCompareExchangePointer((void * volatile *) &_M_pException, (void *) (_S_nonNull | _cancelStatus), _OldStatus);
if (_XchgStatus == _OldStatus)
break;
_OldStatus = _XchgStatus;
}
//
// Note that this is safe as this will only be called on a chore executing on the collection; therefore it will not be touched by the forking
// thread until after we "_CountUp" which comes after this.
//
void *_pExc = new std::exception_ptr(std::current_exception());
_OldStatus = _M_pException;
for(;;)
{
size_t _cancelStatus = ((size_t)_OldStatus & _S_cancelBitsMask);
void *_pExcWC = (void *)((size_t)_pExc | _cancelStatus);
void *_XchgStatus = _InterlockedCompareExchangePointer((void * volatile *) &_M_pException, _pExcWC, _OldStatus);
if (_XchgStatus == _OldStatus)
break;
_OldStatus = _XchgStatus;
}
}
/// <summary>
/// Potentially rethrows the exception which was set with _RaisedException. The caller has responsibility to ensure that _RaisedException
/// was called prior to calling this and that _M_pException has progressed beyond the _S_nonNull state.
/// </summary>
void _TaskCollectionBase::_RethrowException()
{
//
// The cancellation exception is treated very specially within the runtime. Do not arbitrarily rethrow from here.
//
std::exception_ptr *_pException = _Exception();
if (_pException != NULL && (size_t)_pException != _S_cancelException)
{
std::exception_ptr _curException = *_Exception();
delete _pException;
_M_pException = NULL;
if ( !__uncaught_exception())
std::rethrow_exception(_curException);
}
}
/// <summary>
/// Marks the collection for cancellation and returns whether the collection was thus marked.
/// </summary>
bool _TaskCollectionBase::_MarkCancellation()
{
void *_OldStatus = _M_pException;
for(;;)
{
if ((size_t)_OldStatus & _S_cancelBitsMask)
return false;
void *_XchgStatus = _InterlockedCompareExchangePointer((void * volatile *) &_M_pException,
(void *)((size_t)_OldStatus | _S_cancelStarted),
_OldStatus);
if (_XchgStatus == _OldStatus)
return true;
_OldStatus = _XchgStatus;
}
}
/// <summary>
/// Finishes the cancellation state (changing from _S_cancelStarted to one of the other states). Note that only the
/// thread which successfully marked cancellation may call this.
/// </summary>
void _TaskCollectionBase::_FinishCancelState(size_t _NewCancelState)
{
_ASSERTE(_CancelState() == _S_cancelStarted);
_ASSERTE(_NewCancelState != _S_cancelNone && _NewCancelState != _S_cancelStarted);
void *_OldStatus = _M_pException;
for(;;)
{
void *_XchgStatus = _InterlockedCompareExchangePointer((void * volatile *) &_M_pException,
(void *)(((size_t)_OldStatus & ~_S_cancelBitsMask) | _NewCancelState),
_OldStatus);
if (_XchgStatus == _OldStatus)
break;
_OldStatus = _XchgStatus;
}
}
/// <summary>
/// Called when a cancellation is raised on a chore on a given task collection. This makes a determination of what to do with the exception
/// and stores it for potential transport back to the thread performing a join on a chore collection. Note that every other exception
/// has precedence over a cancellation.
/// </summary>
void _TaskCollectionBase::_RaisedCancel()
{
void *_OldStatus = _M_pException;
for (;;)
{
std::exception_ptr *_pException = (std::exception_ptr *)((size_t)_OldStatus & ~_S_cancelBitsMask);
if (_pException != NULL)
return;
size_t _cancelStatus = ((size_t)_OldStatus & _S_cancelBitsMask);
void *pExcWC = (void *)(_S_cancelException | _cancelStatus);
void *_XchgStatus = _InterlockedCompareExchangePointer((void * volatile *) &_M_pException, pExcWC, _OldStatus);
if (_XchgStatus == _OldStatus)
break;
_OldStatus = _XchgStatus;
}
}
/// <summary>
/// Called in order to determine whether this task collection will interrupt for a pending cancellation at or above it.
///
bool _TaskCollectionBase::_WillInterruptForPendingCancel()
{
//
// We can only perform the interruption point if someone in the parentage chain is actually inlined. The number of times where we get here
// without such should be minimal.
//
// Note that structured collections do not initialize _M_pParent until they are inlined. In order to avoid excess initialization in the
// structured case, we key off that to determine the validity of the field. Note that this check is perfectly okay for task collections
// as well.
//
_TaskCollectionBase *pParent = _SafeGetParent();
while (pParent != NULL)
{
if ((pParent->_IsStructured() && (static_cast<_StructuredTaskCollection *>(pParent))->_IsMarkedForCancellation()) ||
(!pParent->_IsStructured() && (static_cast<_TaskCollection *>(pParent))->_IsMarkedForAbnormalExit()))
return true;
pParent = pParent->_SafeGetParent();
}
return false;
}
/// <summary>
/// Called in order to execute a supposed interruption point.
/// </summary>
void _TaskCollectionBase::_Interrupt(bool _FLocalCondition, int _LocalFlags)
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
ASSERT(pContext != NULL);
if (pContext->IsCanceled() || _FLocalCondition || _WillInterruptForPendingCancel())
{
if (_LocalFlags != 0)
_M_inlineFlags |= _LocalFlags;
throw task_canceled();
}
}
} // namespace details
} // namespace Concurrency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -