【发布时间】:2019-01-31 13:32:10
【问题描述】:
(开始前注意:虽然我的问题很笼统,但我的代码需要使用旧版Visual Studio 2008 MFC应用程序编译,并且必须使用MFC或win32同步,请避免使用ie boost或c++ 11回答)
我正在尝试实现 线程安全管道(具有单个读取器和单个写入器的队列),我执行了以下操作:
template<class T>
class CMultiThreadPipe {
private:
HANDLE hSemaphore, hTerminateEvent1, hTerminateEvent2;
CRITICAL_SECTION listMutex;
CList<T*, T*> list;
public:
CMultiThreadPipe() {
InitializeCriticalSection(&listMutex);
hSemaphore = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
hTerminateEvent1 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
hTerminateEvent2 = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}
// pdata must be allocated with new. The dequeueing thread will delete it
void Enqueue(T* pdata) {
EnterCriticalSection(&listMutex);
list.AddHead(pdata);
LeaveCriticalSection(&listMutex);
ReleaseSemaphore(hSemaphore, 1, NULL);
}
// if Dequeue returns null it means the pipe was destroyed and no further queue method calls are legal
// Dequeue caller is responsible to delete the returned instance
T* Dequeue()
{
HANDLE handles[] = { hTerminateEvent1, hSemaphore };
DWORD waitRes = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (waitRes==WAIT_OBJECT_0) {
SetEvent(hTerminateEvent2);
return NULL; // terminated
}
EnterCriticalSection(&listMutex);
T* elem = list.RemoveTail();
LeaveCriticalSection(&listMutex);
return elem; // handler must delete item
}
void Destroy() {
SetEvent(hTerminateEvent1);
WaitForSingleObject(hTerminateEvent2, INFINITE);
EnterCriticalSection(&listMutex);
POSITION pos = list.GetHeadPosition();
for (int i = 0; i < list.GetCount(); i++) delete list.GetNext(pos);
LeaveCriticalSection(&listMutex);
DeleteCriticalSection(&listMutex);
CloseHandle(hSemaphore);
}
~CMultiThreadPipe() {
Destroy();
}
};
代码是这样使用的:
class QueueData {
public:
QueueData(int i) : m_data(i) {};
int m_data;
};
UINT DequeueThreadProc(LPVOID dummy);
CMultiThreadedPipe<QueueData>* pPipe = NULL;
void main() {
pPipe = new CMultiThreadedPipe<QueueData>();
start new thread running DequeueThreadProc
int counter=0;
for (int counter=0; counter<10; counter++)
{
pPipe->Enqueue(new QueueData(counter));
Sleep(300);
}
delete pPipe;
}
UINT DequeueThreadProc(LPVOID ignore)
{
QueueData* queueData;
while ((queueData = pPipe->Dequeue()) != NULL) {
delete queueData;
Sleep(1000);
};
return 0;
}
我遇到的问题是终止,在上述实现中,当管道被销毁(总是由入队线程)时,它正在等待出队线程知道它在删除队列之前终止。它必须这样做以防止出队线程在管道被销毁后尝试出队的情况。
如果出队线程没有继续调用出队,第一个线程将挂在析构函数中,同样如果出队线程在调用出队之间等待很长时间,第一个线程的析构函数将相应地卡在那里。
我阅读了各种关于它的帖子,没有提到安全销毁。任何帮助表示赞赏!
【问题讨论】:
-
首先你需要使用iocp 来实现——这个对象是专门为你的任务而设计的,并且使用这个代码变得更少和高效。在第二次 - 对多个线程使用的对象使用引用计数 - 这样你就不需要等待删除 - 谁释放了最后一个引用 - 称为析构函数。并且不需要与其他线程同步
-
为什么有这么多“结构”?我会采用更简单的实现,没有信号量、列表或终止事件,只有两个关键部分,一个用于读取器,一个用于写入器。
标签: c++ multithreading visual-c++ mfc win32-process