Мои варианты:
1. Самый простой — stdout, он же стандартный вывод. Если перенаправить его в анонимный канал, то родительский процесс сможет читать, что туда пишет дочерний. Если родительский процесс завершится, дочерний будет получать ошибку при записи в канал. Зависание дочернего процесса возможно только в одном случае — если он запишет в канал более 4КБ текста, а родитель не будет этого читать.
2. Аналогичный первому — создать пару TCP-сокетов, соединенных друг с другом. Достоинство — дочерний процесс теперь может использовать неблокирующий режим, что предотвратит его блокировку (ценой потери части данных в том случае, когда родитель их не читает).
3. Просто использовать циклический буфер в разделяемой памяти, с односторонней установкой некоторого события. Можно даже использовать буфер размера 1 — то есть всегда записывать в одно и то же место. Данные могут теряться, но для уведомления о прогрессе это несущественно.
4. Использовать общий семафор — дочерний процесс делает Release, родитель — Wait. Недостаток — невозможно асинхронное ожидание, нет передачи, собственно, сообщений — только подсчет.