Почему мой объект становится пустым из одной строки в другую? - Может ли это быть аппаратная вещь?
Первое, что нужно сказать: я программирую на относительно неизвестном языке: 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. Как видите, он должен выдать ошибку. Но это никогда не происходит.
Кто-нибудь видел такое поведение раньше? Я не могу этого объяснить. Как я уже сказал: отладка действительно сложна в этом случае. Я мог бы просто разбить его на более мелкие классы и, наконец, код, который вы видите здесь. Я также не могу просто идти шаг за шагом через программу с помощью отладчика, потому что тогда не происходит ошибки. Может кто-то может придумать что-то, что может вызвать ошибку в этот момент?
Я знаю, это много кода, но я не мог сделать его короче.
2 ответа
Проблема заключалась в следующем: когда я пытался отладить программу немного больше, иногда включался отладчик и показывал мне, где, по мнению отладчика, произошла ошибка. Это не произошло там, но я смог использовать функцию step-In отладчика. В результате получилось: он превратился в библиотеку, которая используется для сетевых методов. Я не использую эту библиотеку нигде в проекте. Поэтому я попробовал немного дальше, и реальное решение было: удалите Blitzmax и переустановите его. Теперь все работает отлично. Похоже, что компоновщик был сломан как-то.
Вы в основном пишете одновременно в поток. Если DebugLog
не является реентерабельным (например, есть внутренний статический буфер), вы получите нарушение произвольного доступа. На более быстрой машине этого, возможно, можно избежать, поскольку в очереди сообщений будет происходить конфликт, следовательно, у каждого потока будет время для выполнения полного цикла самостоятельно.
Решение состоит в том, чтобы заблокировать использование этой функции (вы можете создать оболочку функции, которая реализует эту блокировку независимо от обработки очереди).