C++关键部分不起作用
我的关键部分代码不起作用!!! Backgrounder.run是否能够修改MESSAGE_QUEUE g_msgQueue和LockSections析构函数尚未被调用!!!C++关键部分不起作用
额外的代码:在一个
typedef std::vector<int> MESSAGE_LIST; // SHARED OBJECT .. MUST LOCK!
class MESSAGE_QUEUE : MESSAGE_LIST{
public:
MESSAGE_LIST * m_pList;
MESSAGE_QUEUE(MESSAGE_LIST* pList){ m_pList = pList; }
~MESSAGE_QUEUE(){ }
/* This class will be shared between threads that means any
* attempt to access it MUST be inside a critical section.
*/
void Add(int messageCode){ if(m_pList) m_pList->push_back(messageCode); }
int getLast()
{
if(m_pList){
if(m_pList->size() == 1){
Add(0x0);
}
m_pList->pop_back();
return m_pList->back();
}
}
void removeLast()
{
if(m_pList){
m_pList->erase(m_pList->end()-1,m_pList->end());
}
}
};
class Backgrounder{
public:
MESSAGE_QUEUE* m_pMsgQueue;
static void __cdecl Run(void* args){
MESSAGE_QUEUE* s_pMsgQueue = (MESSAGE_QUEUE*)args;
if(s_pMsgQueue->getLast() == 0x45)printf("It's a success!");
else printf("It's a trap!");
}
Backgrounder(MESSAGE_QUEUE* pMsgQueue)
{
m_pMsgQueue = pMsgQueue;
_beginthread(Run,0,(void*)m_pMsgQueue);
}
~Backgrounder(){ }
};
int main(){
MESSAGE_LIST g_List;
CriticalSection crt;
ErrorHandler err;
LockSection lc(&crt,&err); // Does not work , see question #2
MESSAGE_QUEUE g_msgQueue(&g_List);
g_msgQueue.Add(0x45);
printf("%d",g_msgQueue.getLast());
Backgrounder back_thread(&g_msgQueue);
while(!kbhit());
return 0;
}
#ifndef CRITICALSECTION_H
#define CRITICALSECTION_H
#include <windows.h>
#include "ErrorHandler.h"
class CriticalSection{
long m_nLockCount;
long m_nThreadId;
typedef CRITICAL_SECTION cs;
cs m_tCS;
public:
CriticalSection(){
::InitializeCriticalSection(&m_tCS);
m_nLockCount = 0;
m_nThreadId = 0;
}
~CriticalSection(){ ::DeleteCriticalSection(&m_tCS); }
void Enter(){ ::EnterCriticalSection(&m_tCS); }
void Leave(){ ::LeaveCriticalSection(&m_tCS); }
void Try();
};
class LockSection{
CriticalSection* m_pCS;
ErrorHandler * m_pErrorHandler;
bool m_bIsClosed;
public:
LockSection(CriticalSection* pCS,ErrorHandler* pErrorHandler){
m_bIsClosed = false;
m_pCS = pCS;
m_pErrorHandler = pErrorHandler;
// 0x1AE is code prefix for critical section header
if(!m_pCS)m_pErrorHandler->Add(0x1AE1);
if(m_pCS)m_pCS->Enter();
}
~LockSection(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE2);
if(m_pCS && m_bIsClosed == false)m_pCS->Leave();
}
void ForceCSectionClose(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE3);
if(m_pCS){m_pCS->Leave();m_bIsClosed = true;}
}
};
/*
Safe class basic structure;
class SafeObj
{
CriticalSection m_cs;
public:
void SafeMethod()
{
LockSection myLock(&m_cs);
//add code to implement the method ...
}
};
*/
#endif
两个问题。我不知道第一个,但关键部分很容易解释。后台线程并不想要锁,因此当然不会被阻止。您需要使关键部分对象crt
对线程可见,以便它可以锁定它。
使用这个锁类的方式是,你想序列化代码的每一部分必须创建一个LockSection
对象,并坚持下去,直到系列化块的结尾:
主题1:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 1
}
线程2:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 2
}
请注意,它必须是在要序列化的每个代码块中使用的相同临界区实例crt
。
您试图在弹出后返回最后一个元素。
你的后台线程需要访问同一个CriticalSection
对象,它需要创建LockSection
对象来锁定它 - 锁定是协作的。
此代码有一些问题。
首先,从标准容器派生几乎总是一个不好的主意。在这种情况下,您正在使用私有继承,这可以减少问题,但不会完全消除它们。无论如何,你似乎并没有把继承放在很多(任何?)的地方。即使你已经从MESSAGE_LIST
(它实际上是std::vector<int>
)派生出MESSAGE_QUEUE
,但是无论如何,都会将指向MESSAGE_LIST
的实例的指针嵌入到MESSAGE_QUEUE
中。其次,如果你打算用一个队列来进行线程之间的通信(我认为一般是个好主意),你应该在队列操作中使锁定固有,而不是要求每个线程来管理锁定正确地在自己。
第三,一个vector
不是一个特别适合表示队列的数据结构,除非你打算使它成为固定大小,并且大致像环形缓冲区那样使用它。这也不是一个坏主意,但它与你所做的完全不同。如果你打算让大小变化,那么你可能会更好地从一个deque开始。第四,错误处理(0x1AE1,0x1AE2等)中的幻数很不透明。至少,你需要来给这些有意义的名字。你有一个评论不是使用在任何地方接近清除。
最后,如果您要为编写线程安全队列编写代码的所有麻烦,您可以将其设置为通用的,以便它可以保存任何您想要的数据,而不是专用它到一个特定的类型。
最终,你的代码似乎并没有保存客户端大量的工作或麻烦了,直接使用Windows功能。大多数情况下,您只是以略有不同的名称提供了相同的功能。
IMO,线程安全的队列应该处理内部几乎所有的工作,让客户端代码,可就像任何其他队列中使用它。
// Warning: untested code.
// Assumes: `T::T(T const &) throw()`
//
template <class T>
class queue {
std::deque<T> data;
CRITICAL_SECTION cs;
HANDLE semaphore;
public:
queue() {
InitializeCriticalSection(&cs);
semaphore = CreateSemaphore(NULL, 0, 2048, NULL);
}
~queue() {
DeleteCriticalSection(&cs);
CloseHandle(semaphore);
}
void push(T const &item) {
EnterCriticalSection(&cs);
data.push_back(item);
LeaveCriticalSection(&cs);
ReleaseSemaphore(semaphore, 1, NULL);
}
T pop() {
WaitForSingleObject(semaphore, INFINITE);
EnterCriticalSection(&cs);
T item = data.front();
data.pop_front();
LeaveCriticalSection(&cs);
return item;
}
};
HANDLE done;
typedef queue<int> msgQ;
enum commands { quit, print };
void backgrounder(void *qq) {
// I haven't quite puzzled out what your background thread
// was supposed to do, so I've kept it really simple, executing only
// the two commands listed above.
msgQ *q = (msgQ *)qq;
int command;
while (quit != (command = q->pop()))
printf("Print\n");
SetEvent(done);
}
int main() {
msgQ q;
done = CreateEvent(NULL, false, false, NULL);
_beginthread(backgrounder, 0, (void*)&q);
for (int i=0; i<20; i++)
q.push(print);
q.push(quit);
WaitForSingleObject(done, INFINITE);
return 0;
}
+1 - 今年,我已经*这两次同意的躺椅和给予好评:( –
感谢大卫。我修改了帖子,所以现在是一个问题,最重要的一个问题。我想这意味着我必须在Backgrounder :: Run中使用LockSection! –
我现在有这样的代码:if(void *的)参数表是2点的指针,你如何提取它们的每一个?例如_beginthread(运行,0,(无效*)(m_pMsgQueue,m_pLc)); ... static void __cdecl Run(void * args){p1 = arg1; p2 = arg2; }? –
这是一个不同的问题。在评论中无法真正解决它。随意问一个新问题。 –