首先要说的是:我使用一种相对未知的语言进行编程:Blitzmax,这是一种面向对象的基本方言。
我的问题如下:我编写了一个在自己的线程中运行的调试管理器。因此,从程序中的每个位置(这将是一场游戏),您都可以将调试或错误消息添加到经理的队列中。在它自己的线程中,它将从队列中获取消息并通过将它们写入文件来处理它们,并且(如果消息具有当前选择的 Debuglevel、Debugcategory 和 outputcategory,它们只是枚举)将其写入控制台。
现在我在三个系统上测试了这个程序:我的台式电脑,它有 Windows 8 作为操作系统,我自己的笔记本电脑有 Windows 7 和一个朋友的笔记本电脑也有 Windows 7。在我的电脑和我朋友的笔记本电脑上一切都很好。但是在我自己的笔记本电脑上,几乎每次都会在经理处理消息时出现“EXCEPTION_ACCESS_VIOLATION”错误。有时程序运行良好,但大多数时候它会因这个错误而崩溃。即使在调试模式下,也不会显示任何行或堆栈跟踪,这使得调试非常困难。
我将所有需要的类分解为最少的属性和功能,以便更容易找到问题。现在队列只是一个列表(在 Blitzmax 中内置),消息只有一个属性,它是一个字符串。此外,调试管理器仅将消息写入控制台,而不将其传递给将其写入文件等的进程方法。
所以实际需要的代码如下。
这是消息:
Type TThreadsafeMessage
Field complete_String:String
Method New_ThreadsafeMessage:TThreadsafeMessage(actual_Message:String, from_File:String, debugCategory:TDebugCategory_Enum, ..
debugLevel:TDebugLevel_Enum, outputCategory:TOutputCategory_Enum, from_Class:String = "", from_Method:String = "")
'Just create the string from the parameters.
Self.complete_String = actual_Message + " | " + from_File + "/" + from_Class + "/" + from_Method
Return Self
End Method
Method ToString:String()
'Just return the string attribute:
Return Self.complete_String' out_String
End Method
Method toString_Formatted_For_File:String()
Return Self.ToString()
End Method
Method toString_Formatted_For_Console:String()
Return Self.ToString()
End Method
End Type
这是队列:
Type TThreadsafeQueue
'Predefined list.
Field list:TList
Method New()
Self.list = New TList
End Method
Method isEmpty:Byte()
Return Self.list.IsEmpty()
End Method
Method enqueue(to_Enqueue:Object)
'Add object to list
Self.list.AddLast(to_Enqueue)
End Method
Method dequeue:Object()
Return Self.list.RemoveFirst()
End Method
End Type
这是向调试管理器添加消息的方法:
Function enqueueMessage(message_To_Enqueue:TThreadsafeMessage)
'Test message for null pointer.
If(message_To_Enqueue = Null) Then
Throw New TNullpointer_Exception.NewException("'message_To_Enqueue' is NULL.", "TDebugmanager.bmx", ..
"TDebugmanager", "enqueueMessage")
EndIf
'Lock mutex for threadsafety.
LockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Enqeue message in the queue
TDebugmanager.getSingleton_Instance().message_Queue.enqueue(message_To_Enqueue)
'Tell the update thread there is a message
SignalCondVar(TDebugmanager.getSingleton_Instance().sleep_ConditionVariable)
'Free the mutex for update thread.
UnlockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
End Function
现在这里是调试管理器的(当前较小的)更新功能:
Function _update:Object(thread_Object:Object)
'Do this over and over till the queue is empty AND the debugmanager is shut down
Repeat
Local message_To_Process:TThreadsafeMessage = Null
'Lock mutex for thread safety
LockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Queue epmty...
If(TDebugmanager.getSingleton_Instance().message_Queue.isEmpty()) Then
'... Wait for a signal from the main thread
WaitCondVar(TDebugmanager.getSingleton_Instance().sleep_ConditionVariable, ..
TDebugmanager.getSingleton_Instance().queue_Mutex)
Else
'...Get the next message from the queue.
message_To_Process = TThreadsafeMessage(TDebugmanager.getSingleton_Instance().message_Queue.dequeue())
EndIf
'Unlock the mutex.
UnlockMutex(TDebugmanager.getSingleton_Instance().queue_Mutex)
'Check if the message is NULL.
If(message_To_Process = Null) Then
Throw "Got null message from queue."
EndIf
'Actually the _processMessage method is used. But for debugging
'it is commented out.
' TDebugmanager.getSingleton_Instance()._processMessage(message_To_Process)
'Write the message to the console.
'HERE is the error.
'See in the following description under the code section.
DebugLog("Message processed: " + message_To_Process.complete_String)
Until TDebugmanager.isFinished()
End Function
所以在它在更新函数中说“这里是错误”的位置。问题如下:如果此行被注释掉或删除,程序在我的笔记本电脑上运行良好,没有错误发生。但是如果有这条线,那么大多数时候都会发生错误。例如,在以下情况下会抛出“EXCEPTION_ACCESS_VIOLATION”:堆栈溢出发生在某处。或者当您尝试访问 NULL 对象时。实际上所有试图从被禁止的内存中读取或写入的东西。真正奇怪的是:仅在前几行,我检查了我从队列中得到的消息是否为 NULL。如您所见,它应该会引发错误。但它永远不会。
有没有人见过这样的行为?我无法解释。正如我所说:在这种情况下调试真的很难。我可以把它分解成更小的类,最后是你在这里看到的代码。我也不能只用调试器一步一步地通过程序,因为这样就不会发生错误。有人可能会想到会导致这一刻错误的事情吗?
我知道,这是很多代码,但我不能让它更短。