Я хочу, чтобы логическое значение было истинным перед выполнением блока кода, и я хочу, чтобы оно фактически блокировало поток, в котором оно находится. Вариант использования достаточно прост. У меня есть вариант использования TTS в моем приложении, и я хочу иметь последовательное выполнение, когда TTS говорит, затем что-то происходит, и он говорит снова и так далее, но дело в том, что это полностью зависит от времени. Мне нужно запустить таймер, как только TTS закончит говорить, но оказывается, что метод speak(...)
неблокирующий (видимо), и поэтому в момент, когда он говорит, управление переходит на следующую строку.
Чтобы справиться с этим, я раздобыл переменную isSpeaking
, реализованную с помощью deprecated
OnUtteranceCompletedListener
, и она, как всегда, отлично работает.
Тем не менее, это СУПЕР-СПЕЦИАЛЬНОЕ исполнение, которое я вижу в своей реализации. Переменная, как я упоминал ранее, отлично отслеживает речь, но когда я применяю свой цикл таким образом,
while(speaking){
continue
}
ОН БЛОКИРУЕТСЯ, ПОКА НЕ ПРОИСХОДИТ РЕЧЬ, А ЗАТЕМ КОНТРОЛЬ ПРОСТО ИСЧЕЗАЕТ!!!,
Я помещаю оператор журнала сразу после этого цикла, и как только условие становится ложным, т. е. цикл прерывается, эта часть кода никогда не регистрируется. На самом деле, после этого он вообще ничего не делает. Вроде исполнение "потерял", где-то после этого. Приложение даже не зависает. Я использую Jetpack-Compose, поэтому все анимации с бесконечным повторением работают нормально, но после этого приложение ничего не делает.
Но вот в чем дело — если я заменю свой continue
просто утверждением Log
, это волшебным образом сработает. ВСЕ РАБОТАЕТ, АБСОЛЮТНО НЕТ НЕОБЫЧНЫХ НАБЛЮДЕНИЙ ПРИ ДОБАВЛЕНИИ ОДИН LOG STATMENT.
Я помню, что наблюдал это в детстве, но не был в контакте с сообществом переполнения в тот день, поэтому я никогда не публиковал это. После этого я никогда не делал приложения, использующие TTS, поэтому я не мог ничем поделиться.
Я говорю, что это работает:
while(speaking){
Log.i("WHY?", "speaking")
}
Это больно, так как я не могу использовать вызовы Log
в своем производственном программном обеспечении, официальная документация строго запрещает это. Помощь!
Вы неправильно обрабатываете условие многопоточности, и это будет проблемой. Цикл, который вы используете, ожидает изменения переменной в другом потоке. Во-первых, это работает, только если переменная изменчива. Если нет, интерпретатор не знает, что ему нужно перезагрузиться из памяти, и этот цикл никогда не закончится. Во-вторых, то, что вы делаете, называется занятым ожиданием и является ПЛОХОЙ идеей для проблем с батареей (и если это делается в потоке пользовательского интерфейса, это может привести к тому, что ваше приложение перестанет отвечать на запросы или даже будет убито сторожевым таймером). Вместо этого, если это не поток пользовательского интерфейса, вы должны использовать механизм сигнализации, такой как семафор. Это позволит вам ждать, не простаивая ЦП, пока не будет дан сигнал. Если это поток пользовательского интерфейса, вы вообще не должны этого делать. Вместо этого вы должны заставить прослушиватель речи отправить сообщение обработчику в поток пользовательского интерфейса и выполнить все, что находится после цикла, в ответ на это сообщение.
У вас случайно нет находчивых ссылок, где я могу изучить все это? Кроме того, как упоминалось выше, я использую Jetpack-Compose в своих проектах, поэтому сопрограммы используются повсеместно. Я использую диспетчер ввода-вывода для запуска этого, который, как вы, возможно, знаете, порождает свой собственный пул потоков, поэтому эта работа определенно выполняется вне потока пользовательского интерфейса.
Хорошо, это хорошо. В этом случае вы можете использовать сигнальный механизм. Или просто запустите следующий код в распознавателе речи для начала.
Мой основной фокус - необъяснимое дело с тем фактом, что «с / без волатильности это работает, если добавляется оператор журнала, и абсолютно не работает, когда используется просто продолжение или пустой цикл while». Я могу согласиться с тем фактом, что волатильность имеет значение, и это действительно могло быть фактором, вызывающим, казалось бы, бесконечный цикл, но ПОЧЕМУ, без каких-либо изменений в природе переменной, добавление одного вызова Log
заставляет цикл работать так, как ожидалось? Это необъяснимый момент, который я хотел бы прояснить, сэр. Спасибо
без volatile интерпретатор может выбрать, загружать его из памяти или нет. Не будет, если не нужно, будет, если понадобится. Оператор журнала заставил что-то в интерпретаторе решить, что ему нужно снова загрузить его из памяти. Скорее всего, он сбрасывал регистры ЦП с помощью вызова функции, или используемый им ABI не требовал вызова функции для восстановления регистра, который он использовал для хранения этого значения. Но там не на что можно положиться, другой интерпретатор Java или даже другая версия этого могут сделать другой выбор.
Вау... Ужасно, но... Я приму это как правильный ответ.
Вскоре я опубликую реализацию компоновки, чтобы лучше визуализировать эффект.