FYI, событие OnBeforeCommandHandler
не является правильным местом для чтения команд с TIdCmdTCPServer
.Вы должны добавить запись для каждой команды в свою коллекцию CommandHandlers
, а затем назначить обработчик OnCommand
для каждой записи.Событие OnBeforeCommandHandler
запускается до того, как TIdCmdTCPServer
проанализирует полученную команду.Это нормально для целей ведения журнала, просто убедитесь, что вы не используете его для управления логикой обработки.Оставьте это отдельным OnCommand
событиям.
Но в любом случае чтение команд выполняется в рабочем потоке.Вы не синхронизируете с основным потоком пользовательского интерфейса при добавлении полученных команд в свой пользовательский интерфейс.Вы ДОЛЖНЫ синхронизироваться.Есть много способов сделать это - TThread.Synchronize()
, TThread.Queue()
, TIdSync
, TIdNotify
, (Send|Post)Message()
и т. Д., Просто назвать несколько.
Что еще более важно, у вас есть 2 потока (или больше, в зависимости от того, сколько клиентов подключено одновременно), которые борются за одну и ту же глобальную переменную, вообще не синхронизируя доступ к ней.Вам нужна блокировка вокруг переменной, например TCriticalSection
или TMutex
, или использование класса TIdThreadSafeString
в Indy.
Но это не решит условия гонки, которые есть в вашем коде.Между временем, когда ваш OnBeforeCommandHandler
назначает новое значение для command
, и временем, когда оно читает command
назад, чтобы добавить его в пользовательский интерфейс, ваш TSupervisorThread
может изменять command
.Это именно то, что вы видите, происходит.Это не аномалия в Indy, это проблема синхронизации в вашем коде.
Самое простое решение этого состояния гонки - просто добавить AData
в ваш интерфейс вместо command
.Таким образом, не имеет значения, если TSupervisorThread
изменит command
, ваш пользовательский интерфейс его не увидит.
Но почему вы вообще используете глобальную переменную command
?Какова его настоящая цель?Вы пытаетесь заставить внешний поток изменить команды, которые TIdCmdTCPServer
анализирует?Вы не контролируете, какие клиенты получают парсинг реальных команд, а какие получают фальшивые команды.Почему вы это делаете?
Кроме того, если TSupervisorThread
выполнять 99% своей работы в основном потоке пользовательского интерфейса, это плохое использование рабочего потока, вы можете просто использовать TTimer
впользовательский интерфейс вместоВ противном случае вам нужно лучше координировать свои потоки, например, используя TEvent
объекты для сигнализации, когда назначено command
, и когда оно сброшено.
Я думаю, вам нужно переосмыслить свой дизайн.