0

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

Моя проблема заключается в следующем: Я написал debugmanager, который работает в своем потоке. Поэтому из каждой позиции в программе (это будет игра) вы можете добавить debug- или errormessages в очередь менеджера. В своем потоке он будет извлекать сообщения из очереди и обрабатывать их, записывая их в файл и (если в сообщении есть текущие выбранные Debuglevel, Debugcategory и outputcategory, которые являются только перечислениями), напишите его на консоль.

Теперь я тестировал программу на трех системах: мой настольный ПК с ОС Windows 8 в качестве ОС, мой собственный ноутбук с Windows 7 и ноутбук друга, который также имеет окна 7. На моем компьютере и ноутбуке моего друга Все отлично. Но на моем собственном ноутбуке я почти каждый раз получаю сообщение об ошибке «EXCEPTION_ACCESS_VIOLATION», когда менеджер обрабатывает сообщения. Иногда программа работает нормально, но большую часть времени она ломается с этой ошибкой. Даже в debugmode не отображается строка или stacktrace, что очень затрудняет ее отладку.

Я сломал все необходимые классы до минимума атрибутов и функциональности, чтобы облегчить поиск проблемы. Теперь очередь - это просто список (который изначально встроен в Blitzmax), и сообщение имеет только один атрибут, который является строкой. Также debugmanager только записывает сообщение в консоль, не передавая его методу процесса, который записывает его в файл и т. Д.

Таким образом, действительно нужен код.

Это сообщение:

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 

Вот метод, который добавляет сообщения в debugmanager:

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 

Теперь здесь (в настоящее время меньше) функция обновления debugmanager:

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» вызывается, например, когда: где-то происходит переток stackoverflow. Или когда вы пытаетесь получить доступ к объекту NULL. На самом деле все, что пытается читать или писать из запрещенной памяти. Странная вещь: только несколько строк раньше, я проверяю, является ли сообщение, которое я получил из очереди, NULL. Должно возникнуть ошибка, как вы можете видеть. Но этого никогда не бывает.

Кто-нибудь видел такое поведение раньше? Я не могу это объяснить. Как я уже сказал: отладка в этом случае очень тяжелая. Я мог бы просто разбить его на более мелкие классы и, наконец, код, который вы видите здесь. Я также не могу просто пойти шаг за шагом через программу с отладчиком, потому что тогда ошибка не возникает. Может кто-нибудь может подумать о чем-то, что может вызвать ошибку в этот момент?

Я знаю, это много кода, но я не мог сделать его короче.

+0

Если вы действительно сомневаетесь в проблеме переполнения стека, попробуйте увеличить лимит стека для программы, а затем убедитесь, что вы все еще сталкиваетесь с проблемой на той же строке .../ –

+0

В настоящее время я тестирую этот класс только с помощью тестовая программа. В этой тестовой программе некоторое количество сообщений добавляется в очередь и обрабатывается. Он также выходит из строя только с 10 сообщениями. И нет существенного увеличения использования ОЗУ. Я только хотел показать, сколько вещей есть, что может вызвать такой тип ошибки. Я не считаю, что это размер стека, потому что я написал гораздо больше программ с этим языком, не меняя размер стека или использование ОЗУ. – M0rgenstern

ответ

0

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

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

+0

Я попробовал то, что вы предложили. Итак, я написал функцию-обертку для debuglog, которая блокирует мьютекс, затем вызывает debuglog, а затем снова открывает мьютекс. Но это ничего не изменило. Ошибка все еще происходит. – M0rgenstern

+0

Извините, я не программист на блиц-карте, что-то там, скорее всего, ускользает от меня. – didierc

+0

'message_To_Process.complete_String', что там происходит? Это вызов метода? – didierc

0

Проблема была в следующем: Когда я попытался отлаживать программу немного больше, иногда отладчик пнул и показал мне, где отладчик думал, что произошла ошибка. Это не произошло там, но я смог использовать функцию step-In отладчика. В результате получилось: оно перешло в библиотеку, которая используется для сетевых методов. Я не использую эту библиотеку в любом месте проекта. Итак, я попробовал немного дальше, и фактическое решение было: Deinstall Blitzmax и переустановить его. Теперь все работает нормально. Кажется, что линкер был сломан каким-то образом.