У меня есть сценарий C ++, который проверяет, должно ли быть выполнено какое-либо действие, и, если это так, запускает правильный сценарий C ++ процессора. Однако, поскольку он запускается каждые x минут, он также проверяет, не работает ли процессор с использованием файлов блокировки.
Я использую следующую функцию для получения блокировки:
int LockFile(string FileNameToLock) {
FileNameToLock += ".lock";
int fd = open(FileNameToLock.c_str(), O_RDWR | O_CREAT, 0666);
int rc = flock(fd, LOCK_EX | LOCK_NB);
if (rc || rc == -1) {
cout << errno << endl;
cout << strerror(errno) << endl;
return -1;
}
return fd;
}
Код, который выполняется:
[...]
if (LockFile(ExecuteFileName, Extra) == -1) {
cout << "Already running!" << endl; //MAIN IS ALREADY RUNNING
//RETURNS ME Resource temporarily unavailable when processor is running from an earlier run
exit(EXIT_SUCCESS);
}
if (StartProcessor) { //PSEUDO
int LockFileProcessor = LockFile("Processor");
if (LockFileProcessor != -1) {
string Command = "nohup setsid ./Processor"; //NOHUP CREATES ZOMBIE?
Command += IntToString(result->getInt("Klantnummer"));
Command += " > /dev/null 2>&1 &"; //DISCARD OUTPUT
system(Command.c_str());
//STARTS PROCESSOR (AS ZOMBIE?)
}
}
Первый запуск работает хорошо, Однако, когда основной скрипт выполняется снова, файл блокировки возвращает -1, что означает, что произошла ошибка (только когда процессор все еще работает). Errno равно 11, что приводит к сообщению об ошибке: Resource temporarily unavailable
, Обратите внимание, что это происходит только тогда, когда (зомби) процессор все еще работает. (Тем не менее, основной сценарий уже завершен, который должен закрыть дескриптор файла?)
Почему-то зомби держит дескриптор файла для файла блокировки основного скрипта открытым ???
Я понятия не имею, где искать эту проблему.
РЕШИТЬ:
смотри мой ответ
Нет 11 EAGAIN/EWOULDBLOCK
это просто означает, что вы не можете получить блокировку, потому что ресурс уже заблокирован (см. документация). Вы получили эту ошибку (вместо блокировки поведения) из-за LOCK_NB
флаг.
РЕДАКТИРОВАТЬ: После некоторого обсуждения кажется, что проблема связана с flock()
блокировки сохраняются при обработке. Чтобы избежать этой проблемы, я рекомендую не использовать flock()
на всю жизнь, но вместо этого прикасайтесь и удаляйте при выходе:
file.lock
существует тогда выходfile.lock
и начать обработкуfile.lock
на выходе.Конечно, здесь есть условия гонки. Для обеспечения безопасности вам понадобится еще один файл с flock
:
flock(common.flock)
file.lock
существует тогда выходfile.lock
flock(common.flock)
file.lock
на выходеНо это имеет значение, только если вы ожидаете одновременных звонков main
, Если вы этого не сделаете (вы сказали, что cron запускает процесс каждые 10 минут, здесь нет гонки), тогда придерживайтесь первой версии.
ПримечаниеВот простая реализация такой (несинхронизированной) блокировки файла:
#include <string>
#include <fstream>
#include <stdexcept>
#include <cstdio>
// for sleep only
#include <chrono>
#include <thread>
class FileLock {
public:
FileLock(const std::string& path) : path { path } {
if (std::ifstream{ path }) {
// You may want to use a custom exception here
throw std::runtime_error("Already locked.");
}
std::ofstream file{ path };
};
~FileLock() {
std::remove(path.c_str());
};
private:
std::string path;
};
int main() {
// This will throw std::runtime_error if test.xxx exists
FileLock fl { "./test.xxx" };
std::this_thread::sleep_for(std::chrono::seconds { 5 });
// RAII: no need to delete anything here
return 0;
};
Требуется C ++ 11. Обратите внимание, что эта реализация не безопасна при условии гонки, т.е. flock()
конструктор, но в этой ситуации это, вероятно, будет хорошо (то есть, когда вы не запускаете main параллельно).
Я решил эту проблему, так как команды system и fork, похоже, передаются стаду, сохраняя команду для выполнения в векторе. Разблокируйте файл блокировки прямо перед циклом вектора Commands и выполните каждую команду. Это оставляет основной с очень маленьким промежутком бега, пока он не заблокирован, но сейчас он, кажется, работает отлично. Это также поддерживает неблагодарное завершение.
[...]
if (LockFile(ExecuteFileName, Extra) == -1) {
cout << "Already running!" << endl; //MAIN IS ALREADY RUNNING
//RETURNS ME Resource temporarily unavailable when processor is running from an earlier run
exit(EXIT_SUCCESS);
}
vector<string> Commands;
if (StartProcessor) { //PSEUDO
int LockFileProcessor = LockFile("Processor");
if (LockFileProcessor != -1) {
string Command = "nohup setsid ./Processor"; //NOHUP CREATES ZOMBIE
Command += IntToString(result->getInt("Klantnummer"));
Command += " > /dev/null 2>&1 &"; //DISCARD OUTPUT
Commands.push_back(Command);
}
}
//UNLOCK MAIN
if (UnlockFile(LockFileMain)) {
for(auto const& Command: Commands) {
system(Command.c_str());
}
}