Простым решением является создание скрипта start.sh, который запускает Java через nohup, а затем сохраняет PID в файл:
nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt
Тогда ваш стоп-скрипт stop.sh будет читать PID из файл и убить приложение:
PID=$(cat pid.txt)
kill $PID
Конечно, я не рассмотрел некоторые детали, например, проверить, существует ли процесс и удалить pid.txt
, если вы закончили.
Поскольку требуется вызвать fann_destroy_train_data
, вы можете использовать C ++ и RAII, используя следующую обертку:
struct fann_wrapper
{
fann_train_data *td;
fann_wrapper(fann_train_data* p) : td(p) {}
~fann_wrapper() { fann_destroy_train_data(td); }
};
//...
for (int i = 1; i <= epochs; ++i) {
for (std::vector<std::filesystem::path>::iterator it = batchFiles.begin(); it != batchFiles.end(); ++it) {
struct fann_train_data *data = fann_read_train_from_file(it->string().c_str());
// the next line ensures that fann_destroy_train_data is called
fann_wrapper fw(data);
fann_shuffle_train_data(data);
float error = fann_train_epoch(ann, data);
} // when this curly brace is encountered, the fann_destroy_train_data is always called
}
fann_wrapper
просто содержит указатель fain_train_data
, и при уничтожении fann_wrapper
, fann_train_data
уничтожен.
Причина, по которой это намного безопаснее, чем метод C
, заключается в том, что может быть выдано возможное исключение (по любой причине). Если выдается исключение, то fann_train_data
будет всегда уничтожаться при использовании fann_wrapper
. Эту гарантию нельзя сделать с помощью метода C
, поскольку исключение полностью пропустит любую строку, содержащую fann_destroy_train_data
.
Пример:
for (int i = 1; i <= epochs; ++i) {
for (std::vector<std::filesystem::path>::iterator it = batchFiles.begin(); it != batchFiles.end(); ++it) {
struct fann_train_data *data = fann_read_train_from_file(it->string().c_str());
fann_shuffle_train_data(data);
float error = fann_train_epoch(ann, data);
fann_destroy_train_data(data); // this line is not executed if an exception is thrown above, thus a memory leak
}
}
Вот почему RAII является важной концепцией в C ++. Ресурсы будут очищаться автоматически, независимо от причины выхода исполняемого блока кода (генерируется исключение, выполняется return
и т. Д.).
В C ++ память автоматически освобождается, когда управляющий ею объект выходит из области видимости. (Предполагая, что класс был написан правильно.) Это называется RAII .
Но FANN представляет C API, а не C ++ API. В C вам нужно вручную освободить память, когда вы закончите с ней. Более того, когда библиотека C создает объект для вас, обычно требуется, чтобы вы сказали ему, когда вы закончите с объектом. Библиотека не может самостоятельно определить, когда ресурсы объекта должны быть освобождены.
Соглашение состоит в том, что всякий раз, когда C API предоставляет вам функцию, подобную struct foo* create_foo()
, вы должны искать соответствующую функцию, подобную void free_foo(struct foo* f)
. Это симметрично.
В вашем случае, как первоначально отмечал PaulMcKenzie, вам нужно void fann_destroy_train_data(struct fann_train_data * train_data)
. Из документации , выделено мое:
Уничтожает обучающие данные и должным образом освобождает все связанные данные. Обязательно вызывайте эту функцию после завершения использования обучающих данных.
BLOCKQUOTE>