Почему мой объект становится пустым из одной строки в другую? - Может ли это быть аппаратная вещь?

Первое, что нужно сказать: я программирую на относительно неизвестном языке: 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 не является реентерабельным (например, есть внутренний статический буфер), вы получите нарушение произвольного доступа. На более быстрой машине этого, возможно, можно избежать, поскольку в очереди сообщений будет происходить конфликт, следовательно, у каждого потока будет время для выполнения полного цикла самостоятельно.

Решение состоит в том, чтобы заблокировать использование этой функции (вы можете создать оболочку функции, которая реализует эту блокировку независимо от обработки очереди).

Другие вопросы по тегам