В следующем коде я собираюсь открыть файл и что-то написать.
Поскольку программа запускается одновременно в нескольких потоках, значение log_fd после завершения выполнения функции fopen может быть NULL.
Потом программа вылетает и закрывается.
static void __log_prt__(const char *fmt, va_list ap)
{
// omitted code ...
FILE *log_fd = fopen(def_log_file, "a");
// omitted code ...
fclose(log_fd);
}
Это приведет к ошибке 9: Неверный файловый дескриптор.
Я модифицировал программу так, чтобы она выполняла функцию fopen до тех пор, пока возвращаемое значение не станет равным NULL, как в следующем коде:
static void __log_prt__(const char *fmt, va_list ap)
{
// omitted code ...
FILE *log_fd = fopen(def_log_file, "a");
while (log_fd == NULL) {
log_fd = fopen(def_log_file, "a");
}
// omitted code ...
fclose(log_fd);
}
Таким образом, у программы больше не будет сбоев, вызванных errno 9.
Теперь у меня вопрос, правильно ли это? Есть ли более разумный способ?
Почему параллелизм подразумевает, что fopen может потерпеть неудачу? Просто интересуюсь.
FILE *log_fd = fopen(def_log_file, "a");
while (log_fd == NULL) {
log_fd = fopen(def_log_file, "a");
}
Такой подход кажется очень оптимистичным. На справочной странице я насчитал около 42 различных ошибок, которые могут привести к сбою fopen ()
.¹
Если fopen ()
вернет NULL
, нет никакой гарантии, что его отзыв волшебным образом исправит условия, которые привели к его сбою.
Помнить:
[1] — включая ENOMEM
(Ошибка отсутствия памяти), после чего вы должны прервать выполнение.
Спасибо, я добавил в свою программу логику обработки ошибок, которая возвращает NULL для функции fopen.
Почему бы не добавить правильную обработку ошибок? Вы знаете, что
fopen
может дать сбой и вернуть нулевой указатель, но правильное решение почти никогда не состоит в том, чтобы просто ждать, пока его можно будет открыть (что может быть никогда). Вместо этого изящно потерпеть неудачу или в худшем случае сообщить пользователю и выйти из программы.