LINUX.ORG.RU

Класс-наследник разучился писать логи.

 , ,


0

1

Доброго времени суток!

Продолжаю изучать классы. В данный момент меня в ступор поставило следующее: если вместо базового класса, использовать его потомка, созданного после вызова fork(), то программа перестает уметь писать логи.

Хм... наверное, проще показать код:тыц!

Если в 27 строчке файла main.cpp заменить TUSB_Daemon на TDaemon, то логи вестись будут (где? - смотрим в файле usb_daemon_conf.h). За ведение логов отвечает функция WriteLog, которая вообще к классу не относится. То же самое относится и к cout в дочернем процессе, даже если STDOUT_FILENO не закрыт.

При этом компиляция проходит успешно. Объясните, пожалста, почему магия наследования не работает?

★★

Минимальный кусок кода, который это воспроизводит, есть?

Копаться в целом проекте лень.

trex6 ★★★★★
()
Ответ на: комментарий от trex6

void WriteLog(const char* str, ...);

using namespace std;

class TDaemon{
	protected:
		static const unsigned int FD_LIMIT;
		static char PID_FILE[128];
		static char CONFIG_FILE[128];
	public:
		TDaemon(const char* ConfigName);
		~TDaemon(){ };
		virtual void DaemonFunction(unsigned int, void*){};
		int MonitorProc();
		int ReloadConfig();
		int LoadConfig(const char* Filename);
		static void signal_error(int sig, siginfo_t *si, void *ptr);
		int SetFdLimit(int MaxFd);
		int WorkProc();
};

static char Time[10];
char TDaemon::CONFIG_FILE[128];
char TDaemon::PID_FILE[128];
static char LOG_FILE[128];
const unsigned int TDaemon::FD_LIMIT=2048;
char* getTime()
{ //функция возвращает форматированное время
	bzero(Time, 10);
	time_t seconds = time(NULL);
	tm* timeinfo = localtime(&seconds);
	strftime(Time, 9, "%T",timeinfo);
	return Time;
}

void WriteLog(const char* format, ...)
{//функция пишет в лог
	FILE * lf;
	lf=fopen(LOG_FILE,"a");
	va_list args;
	va_start (args, format);
    vfprintf(lf, format, args); //печатаем в файл
    va_end (args);
    fclose(lf);
}

class TUSB_Daemon : public TDaemon{
	private:
		
	public:
		void DaemonFunction(unsigned int, void*);
		TUSB_Daemon(const char* ConfigName) : TDaemon(ConfigName){};
};

int main(int argc, char** argv)
{
    int status;
    int pid;
    // создаем потомка
    pid = fork();
    if (!pid) // если это потомок. Дочь без отца - это ДЕМОН
    {
        TUSB_Daemon daemon(argv[1]);//<---вот это меняем на TDaemon daemon(argv[1]); и все работает.
        // Данная функция будет осуществлять слежение за процессом
        status = daemon.MonitorProc();
        
        return status;
    }
    else // если это родитель
    {
        return 0;
    }
}
aido ★★
() автор топика
Ответ на: комментарий от trex6

Кож конструктора и вызываемых в нем функций необходим?

aido ★★
() автор топика
Ответ на: комментарий от trex6

пастебин заблочен роскомнадзором...

TDaemon::TDaemon(const char* ConfigName){
	// данный код уже выполняется в процессе потомка
        // разрешаем выставлять все биты прав на создаваемые файлы, 
        // иначе у нас могут быть проблемы с правами доступа
        umask(0);
        //Задаем путь к конфигу
        char fullname[128];
        strcpy(fullname,ETC_CONF_DIR);
        strcat(fullname,ConfigName);
        strcpy(CONFIG_FILE, fullname);
        //загружаем конфиг
        LoadConfig(CONFIG_FILE);
        //задаем путь к логу
        bzero(fullname,128);
        strcpy(fullname,LOG_DIR);
        strcat(fullname,PROJ_NAME);
        strcat(fullname,".log");
        strcpy(LOG_FILE, fullname);
        //задаем путь к PID-файлу
        bzero(fullname,128);
        strcpy(fullname,RUN_DIR);
        strcat(fullname,PROJ_NAME);
        strcat(fullname,".pid");
        strcpy(PID_FILE, fullname);
        // создаём новый сеанс, чтобы не зависеть от родителя
        setsid();
        
        // переходим в корень диска, если мы этого не сделаем, то могут быть проблемы.
        // к примеру с размонтированием дисков
        chdir("/");
        // закрываем дискрипторы ввода/вывода/ошибок, так как нам они больше не понадобятся
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
}
aido ★★
() автор топика

Напиши минимальный код, который вопроизводит пример

... и сам найдешь ошибку.

Вот я написал - у меня всё логирует. Значит ошибка где-то в других местах.

P. S. Я в многопоточности, конечно, ни бум-бум, но меня немного напрягает 4-кратный вызов деструктора на каждый объект. Это нормально?

#include <iostream>
#include <iomanip>
#include <unistd.h>

void WriteLog(const std::string str)
{
	std::cout << str << std::endl;
};

class CParent {
public:
	std::string m_id;

	CParent(const std::string id);
	CParent(const CParent & )=delete;
	CParent(CParent && )=delete;

	~CParent();
	void Fn1();
};

class CChild:public CParent {
public:
	CChild (const std::string id);
	CChild(const CChild & )=delete;
	CChild(CChild && )=delete;

	void Fn2();
};

/************************** CParent implementation ****************************/ 

CParent::CParent(const std::string id)
{
	m_id=id;
	WriteLog("CParent construct: " + m_id);
};

CParent::~CParent()
try
{
	WriteLog("CParent destruct: " + m_id);
}
catch(...)
{};

void CParent::Fn1()
{
	pid_t pid=0;

	pid=fork();

	WriteLog( "** CParent function; pid=" + std::to_string(pid) );

};

/************************** CChild implementation *****************************/
CChild::CChild(const std::string id)
:CParent(id)
{
	WriteLog("CChild construct: " + id );
};

void CChild::Fn2()
{
	pid_t pid=0;

	pid=fork();
	WriteLog( "** CChild function; pid=" + std::to_string(pid) );
};

int main()
{
	CParent p("P");
	CChild c("C");

	p.Fn1();
	c.Fn2();

	return 0;
};


CParent construct: P
CParent construct: C
CChild construct: C
** CParent function; pid=1165
** CChild function; pid=1166
CParent destruct: C
CParent destruct: P
** CParent function; pid=0
** CChild function; pid=1167
CParent destruct: C
CParent destruct: P
** CChild function; pid=0
CParent destruct: C
CParent destruct: P
** CChild function; pid=0
CParent destruct: C
CParent destruct: P

Kroz ★★★★★
()
Ответ на: комментарий от aido

это где ж там четырхкратный?

CParent destruct: P повторяется 4 раза. Ровно как и CParent destruct: С.

Kroz ★★★★★
()
Ответ на: комментарий от aido

Шёл от обратного. Если не вызывается, значит не те условия, если не те условия, значит не те значения, а начальных значений не оказалось. Да и код с базовым и производным классом по факту не различается, поэтому оставалось только что-то вроде неинициализированной переменной.

Сейчас ещё проверил, с флагами -O1 -Wall g++ сообщает о ошибке:

daemon.cpp: In member function ‘int TDaemon::MonitorProc()’:
daemon.cpp:130:29: warning: ‘pid’ may be used uninitialized in this function [-Wmaybe-uninitialized]
                 kill(pid, SIGHUP); // перешлем его потомку
Оптимизация для этой диагностики нужна так как она включает расширенный анализ кода, без которого диагностика не сработает.

xaizek ★★★★★
()
Ответ на: комментарий от aido

ты должен мне новые глаза...

почему бы не начать изучение крестов со стандартной библиотеки? всяких там глупых std::string?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.