Переходы между состояниями должны запускаться событием, а не длительной операцией.
Если у вас есть логика, в которой есть какие-либо длинные операции, было бы лучше поместить пользовательский интерфейс в собственный поток, иначе вы не будете отвечать.
Вы всегда можете иметь два независимых конечных автомата в своих собственных потоках, а затем использовать межпотоковую связь для каждого, чтобы запускать друг друга. Передача сообщений, вероятно, самый надежный подход. ( boost :: interprocess :: message_queue может быть излишним, но это будет работать)