Выход из критической секции после сбоя потока

У меня есть поток, выполняющий команды из списка

do
{
commandExec->criticalSection.EnterCS();
if (!commandExec->commands.empty())
{
commandExec->ExecuteCommand(commandExec->commands.front());
commandExec->commands.pop_front();
}
else
commandExec->criticalSection.SuspendThread();
commandExec->criticalSection.LeaveCS();
} while (commandExec->maintainCommandExecution);

и второй поток, который добавляет команды в список:

criticalSection.EnterCS();
commands.push_back(Command(code, parameters));
criticalSection.LeaveCS();
criticalSection.ResumeThread();

Первый поток мог аварийно завершить работу при выполнении команды, поэтому второй поток не мог получить доступ к критическому разделу:

Если поток завершается, пока у него есть владелец критического раздела, состояние критического раздела не определено.
Источник

Итак, каков хороший способ справиться с этой проблемой?
Я мог бы подумать о некоторых решениях, но они кажутся хитрыми (добавление третьего потока, второго критического раздела и т. Д.)

(critSection это просто простая оболочка для CRITICAL_SECTION)

2

Решение

Вы можете создать класс LockCriticalSection, который блокирует критическую секцию в конструкторе и разблокирует критическую секцию в деструкторе.

Затем в своем коде вы размещаете объект LockCriticalSection, где вы хотите начать блокировку. Критическая секция будет освобождена автоматически, когда объект LockCriticalSection выйдет из области видимости (потому что функция завершается правильно или из-за исключения)

Ниже приведен код, который заботится о блокировке и разблокировке критической секции:

/// \brief This class locks a critical section in the
///         constructor and unlocks it in the destructor.
///
/// This helps to correctly release a critical section in
///  case of exceptions or premature exit from a function
///  that uses the critical section.
///
///////////////////////////////////////////////////////////
class LockCriticalSection
{
public:
/// \brief Creates the object LockCriticalSection and
///         lock the specified CRITICAL_SECTION.
///
/// @param pCriticalSection pointer to the CRITICAL_SECTION
///                         to lock
///
///////////////////////////////////////////////////////////
LockCriticalSection(CRITICAL_SECTION* pCriticalSection):
m_pCriticalSection(pCriticalSection)
{
EnterCriticalSection(pCriticalSection);
}

/// \brief Destroy the object LockCriticalSection and
///         unlock the previously locked CRITICAL_SECTION.
///
///////////////////////////////////////////////////////////
virtual ~LockCriticalSection()
{
LeaveCriticalSection(m_pCriticalSection);
}
private:
CRITICAL_SECTION* m_pCriticalSection;
};

И это модифицированный исходный код из вашего вопроса:

do
{
{
LockCriticalSection lock(&criticalSectionToLock);
while (!commandExec->commands.empty())
{
commandExec->ExecuteCommand(commandExec->commands.front());
commandExec->commands.pop_front();
}
} // here the critical section is released
// suspend thread here
} while (commandExec->maintainCommandExecution);
2

Другие решения

Вы можете использовать Mutex вместо критического раздела (но остерегайтесь проблемы, изложенной в Понимание последствий WAIT_ABANDONED).

2

По вопросам рекламы [email protected]