logo
Литература_1 / photon_old

Завершение многопоточной программы

Завершение многопоточного приложения может оказаться мудрёным; вызов функции exit() сделает так, что Ваши потоки просто исчезнут, так что Вам следует убедиться, что Вы не завершите работу, пока другой поток делает что-то такое, что нельзя прервать, например, сохраняет файл.

 Не вызывайте pthread_exit() в потоке, который запер библиотеки Photon'а. Если вы сделаете это, в Вашем приложении будет утечка памяти.

Помните, что все ответные реакции выполняются потоком, который запер библиотеки.

В приложении Photon'а библиотека может вызвать функцию PtExit(), когда закрывается последнее окно Вашего приложения. Если вы не хотите, чтобы это случилось, пока поток выполняет что-нибудь важное, сбросьте признак Ph_WM_CLOSE в ресурсе Pt_ARG_WINDOW_MANAGER_FLAGS Вашего базового окна и обработайте сообщение о закрытии самостоятельно. Вам также необходимо найти все вызовы exit() или PtExit() в Вашем программном коде и принять меры, чтобы Вы не завершили работу до тех пор, пока это не станет безопасным. Если виджет в Вашем базовом окне имеет ответную реакцию типа Done или Cancel, Вы также должны это обработать.

Библиотека Photon'а предлагает несколько механизмов, чтобы сделать обработку этого типа ситуации проще и безопаснее:

Функции, предоставляющие этот счётчик, PtPreventExit() и PtAllowExit(), являются не только потоко-безопасными, но также безопасными в смысле реального времени: они гарантируют выполнение ограниченного объёма машинного кода и никогда не генерируют инверсию приоритета.

Этот механизм считается относительно низкоуровневым и предназначен прежде всего для потоков, которые ничего не делают с функциями Photon'а (возможно, временно – т.е. пока находятся внутри секции PtLeave()/PtEnter() ).

Основанием является то, что определённые вызовы функций Photon'а, которые обычно являются блокирующими, просто завершают вызывающий поток, если висит PtExit() (в противном случае функция PtExit() будет потенциально надолго блокировать). Это также случается, когда поток блокируется перед тем, как другой поток вызывает PtExit(); блокированный поток завершается без возвращения из блокированного вызова. Список вызовов Photon'овских функций, которые явялются "летальными" после того, как другой поток вызвал PtExit(), включает попытки обработки событий, выполнение чего-либо модального, блокирования на переменной состояния с использованием функций PtCondWait() или PtCondTimedWait(), или вызовов PtEnter() или PtLeave().

Чтобы избежать подобных ситуаций, имеется флаг Pt_DELAY_EXIT, который Вы можете передать функции PtEnter() или PtLeave(). Выполнение этого не только помешает функциям PtEnter() или PtLeave() завершить Ваш поток, когда другой поток вызовет PtExit(), но также вызовет неявно PtPreventExit(). Если Ваш поток по какой-либо причине помирает, библиотека знает, что для Вас надо вызвать PtAllowExit(). Флаг Pt_DELAY_EXIT делает Вашу ответную реакцию "сохранить файл" столь простой:

my_callback( ... ) {

PtLeave( Pt_DELAY_EXIT );

save_file(); /* Здесь Вы в безопасности… */

PtEnter( 0 ); /* Но это может убить Вас ­– и это хорошо! */

}

Кроме того, Вы должны обеспечить, чтобы save_file() не пыталась выполнить какие-либо "летальные" вызовы. В частности, Вы не можете поднять всплывающий диалог с сообщением об ошибке, если что-то пошло неправильно. Если Вы хотите поднять всплывающий диалог, который потенциально займёт экран на минуты или часы, Вы должны сделать это перед вызовом PtExit(), например, использованием приёма с Pt_ARG_WINDOW_MANAGER_FLAGS, обсуждённого выше.

Чтобы завершить поток, который выполняет PtMainLoop(), без прекращения работы приложения в целом, вызывайте PtQuitMainLoop().

 Не вызывайте функцию PtMainLoop() в потоке, который не запер библиотеки Photon'а.

Если Вы вызываете PtQuitMainLoop() из главного потока Вашего приложения, приложение прекращает свою работу. Чтобы определить, находитесь ли Вы в главном потоке или нет:

Yandex.RTB R-A-252273-3
Yandex.RTB R-A-252273-4