【发布时间】:2016-06-09 00:08:47
【问题描述】:
我有一个 C++ 中的多线程任务,其中有一个关键代码块。主要要求如下:
- 只有在当前执行完成后,才允许重新输入关键代码(由相同或另一个线程),
- UI 线程在等待另一个当前正在执行关键代码的线程时不能被冻结。
所以我在 C++ Builder 中创建了以下 类 来满足要求。 你觉得有什么问题吗?
非常感谢您提前抽出时间!
类声明/定义:
#include "windows.h"
#include <vector>
#include <algorithm>
class TSyncObject
{
private:
DWORD WorkingThreadId;
std::vector<DWORD> WaitingThreadIds;
TCriticalSection *Section;
HANDLE Event;
//---------------------------------------------------------------------------
bool CanThreadWait(const DWORD ThreadId)
{
bool CanWait;
Section->Enter();
try
{
bool AlreadyWaiting =
std::find(WaitingThreadIds.begin(), WaitingThreadIds.end(), ThreadId) != WaitingThreadIds.end();
CanWait = !AlreadyWaiting && ThreadId != WorkingThreadId && WorkingThreadId;
if (CanWait)
{
WaitingThreadIds.push_back(ThreadId);
}
}
__finally
{
Section->Leave();
}
return CanWait;
}
//---------------------------------------------------------------------------
void Acquire(const DWORD ThreadId)
{
Section->Enter();
try
{
WorkingThreadId = ThreadId;
std::vector<DWORD>::iterator Pos =
std::find(WaitingThreadIds.begin(), WaitingThreadIds.end(), ThreadId);
if (Pos != WaitingThreadIds.end())
{
WaitingThreadIds.erase(Pos);
}
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
void HandleError()
{
Section->Enter();
try
{
if (GetCurrentThreadId() == WorkingThreadId ||
(WaitingThreadIds.empty() && !WorkingThreadId))
{
WorkingThreadId = 0;
SetEvent(Event);
}
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
public:
//---------------------------------------------------------------------------
enum TThreadAcquire {Acquired, WaitEjected, AppTerminated, Failed};
//---------------------------------------------------------------------------
TSyncObject() :
WorkingThreadId(0),
Section(new TCriticalSection()),
Event(CreateEventW(0, 0, 1, 0))
{
}
//---------------------------------------------------------------------------
virtual ~TSyncObject()
{
CloseHandle(Event);
delete Section;
}
//---------------------------------------------------------------------------
TThreadAcquire Acquire()
{
try
{
DWORD CurrentThreadId = GetCurrentThreadId();
if (WaitForSingleObject(Event, 0) != WAIT_OBJECT_0)
{
if (!CanThreadWait(CurrentThreadId))
{
return WaitEjected;
}
while (!Application->Terminated &&
(MsgWaitForMultipleObjects(1, &Event, 0, INFINITE, QS_ALLINPUT) - WAIT_OBJECT_0))
{
Application->ProcessMessages();
}
if (Application->Terminated)
{
return AppTerminated;
}
}
Acquire(CurrentThreadId);
return Acquired;
}
catch (...)
{
HandleError();
return Failed;
}
}
//---------------------------------------------------------------------------
void Release()
{
Section->Enter();
try
{
WorkingThreadId = 0;
SetEvent(Event);
}
__finally
{
Section->Leave();
}
}
//---------------------------------------------------------------------------
};
我会这样使用它:
TSyncObject Sync; // Global for all threads
//...
一个线程使用这样的对象:
TSyncObject::TThreadAcquire Acq = Sync.Acquire();
try
{
if (Acq == TSyncObject::WaitEjected)
{
//...
return;
}
else if (Acq == TSyncObject::AppTerminated)
{
//...
return;
}
else if (Acq == TSyncObject::Failed)
{
//...
return;
}
// critical code block
}
__finally
{
Sync.Release();
}
【问题讨论】:
标签: c++ multithreading winapi c++builder