Reputation: 1
I'm not sure if I developed everything correct.
At least it's working, but is it realy correct? But sometimes I get an error when starting the service. If I try again it's starting.
Thanks for your help.
I developed a Service which creates a Thread "Importer". The Importer read the configuration like connection params from the registry. Here I get sometimes the problem that some parameter could not read.
The Import check for files with extension .jpg in a directory. The path of the directory is also stored in registry. If JPG are existing in directory they will be imported in a database and removed from filesystem. All JPG are imported the Thread "Importer" will sleep for x minutes which is also configured in registry.
The service
//---------------------------------------------------------------------------
void __fastcall TSrvCrateImage::ServiceExecute(TService *Sender) {
while (!Terminated) {
ServiceThread->ProcessRequests(false);
// MyImporter->Resume();
Sleep(1000);
}
}
//---------------------------------------------------------------------------
void __fastcall TSrvCrateImage::ServiceStart(TService *Sender, bool &Started) {
MyImporter = new Importer(false);
bool valid = ReadConfig();
if (valid) {
Started = true;
} else {
Started = false;
}
}
//---------------------------------------------------------------------------
bool __fastcall TSrvCrateImage::ReadConfig() {
UnicodeString msg = MyImporter->ReadConfig();
if (!msg.IsEmpty()) {
LogMessage(msg, EVENTLOG_ERROR_TYPE);
return false;
}
LogMessage("Configuration loaded.", EVENTLOG_INFORMATION_TYPE);
return true;
}
//---------------------------------------------------------------------------
void __fastcall TSrvCrateImage::ServiceStop(TService *Sender, bool &Stopped) {
MyImporter->Terminate();
Stopped = true;
}
The Importer
__fastcall Importer::Importer(bool CreateSuspended)
: TThread(CreateSuspended) {
m_SleepMin = 0;
m_ConfFile = new TRegConfigFile();
}
//---------------------------------------------------------------------------
void __fastcall Importer::Execute() {
try {
while (!Terminated) {
ImportImageFiles();
Sleep(m_SleepMin * 60 * 1000);
}
} catch (Exception &exception) {
SrvCrateImage->LogMessage("Importer::Execute() " + exception.ToString(), EVENTLOG_ERROR_TYPE);
}
}
Thanks a lot
I started the service and sometimes I get errors that some paramters are not existing. I don't know what happen if a problem will occure. Will the service and thread still work? Or not due to bad thread programming...
Upvotes: 0
Views: 230
Reputation: 1
it looks like I have a problem with the thread. I have two configurations that I am loading. In a loop over the configuration I'm processing files.
If a file cannot be processed, an email is sent to the email configuration which is passed in the function.
Sometimes email wich could not processed for configuration 1 are send to configuration two.
__fastcall Importer::Importer(bool CreateSuspended, TRegConfigFile* configFile)
: TThread(CreateSuspended) {
m_ConfFile = configFile;
m_SleepMin = m_ConfFile->ReadImporterDocImportSleepMin();
TStringList* m_BadFileList = new TStringList();
m_DocBarcodeImporter = new TDocBarcodeImporter(userId,
MainDataModule->QrCMHelper1,
MainDataModule->QrMMHelper1,
MainDataModule->QrMMHelper2,
extension,
MainDataModule->SlLnk,
m_BadFileList,
MainDataModule->MMScript01);
}
void __fastcall Importer::Execute() {
try {
while (!Terminated) {
Synchronize(ImportDocFiles);
Sleep(m_SleepMin * 60 * 1000);
}
} catch (Exception &exception) {
SrvCrateDoc->LogMessage("Importer::Execute() " + exception.ToString(), EVENTLOG_ERROR_TYPE);
}
}
void __fastcall Importer::ImportDocFiles() {
TList* mailList = m_ConfFile->GetDocNiederlassungsMailConfigList();
int count = mailList->Count;
for (int i=0; i < count; i++) {
MailConfigNiederlassungDocImport* mailConf = (MailConfigNiederlassungDocImport*)mailList->Items[i];
ImportDocFiles(mailConf);
}
}
void __fastcall Importer::ImportDocFiles(MailConfigNiederlassungDocImport* mailConf) {
try {
MainDataModule->Connect();
m_DocBarcodeImporter->SetIsLoggingActive(m_ConfFile->ReadImporterDocLogging() == 1);
m_DocBarcodeImporter->ImportFiles(mailConf->GetImportDir(), "pdf");
m_DocBarcodeImporter->ProcessBadFiles(mailConf);
m_DocBarcodeImporter->ProcessImportedFiles();
} catch (Exception &e) {
UnicodeString errorMsg = e.Message;
SrvCrateDoc->LogMessage(" Importer::ImportDocFiles ERROR " + errorMsg, EVENTLOG_ERROR_TYPE);
}
MainDataModule->Disconnect();
}
I think that the processing of documents needs longer then Sleep in Execute and the method ImportDocFiles() is executed again but the ImportDocFiles is still running.
Upvotes: 0
Reputation: 598434
I see a number of issues with your code.
get rid of the TService::OnExecute
event handler completely. You don't need it. It is not doing anything useful. TService
will handle SCM requests internally for you when there is no OnExecute
handler assigned.
What is the point of creating a new thread for the importer if you are going to make the service thread dependent on reading the config from the importer? You have two threads fighting over a single config without any synchronization between them. I would suggest having the service thread read in the config before starting the importer thread.
Your service's OnStop
event handler is signaling the importer thread to terminate, but is not waiting for the thread to fully terminate, let alone destroying the thread. It needs to do both.
With that said, try something more like this:
Service:
//---------------------------------------------------------------------------
void __fastcall TSrvCrateImage::ServiceStart(TService *Sender, bool &Started) {
TRegConfigFile *ConfFile = ReadConfig();
if (ConfFile) {
MyImporter = new Importer(false, ConfFile);
Started = true;
} else {
Started = false;
}
}
//---------------------------------------------------------------------------
TRegConfigFile* __fastcall TSrvCrateImage::ReadConfig() {
String msg;
// read config directly, not from importer thread...
TRegConfigFile *ConfFile = new TRegConfigFile();
try {
msg = ...; // read from ConfFile as needed?
}
catch (Exception &exception) {
msg = exception.ToString();
}
if (!msg.IsEmpty()) {
LogMessage(msg, EVENTLOG_ERROR_TYPE);
delete ConfFile;
return NULL;
}
LogMessage("Configuration loaded.", EVENTLOG_INFORMATION_TYPE);
return ConfFile;
}
//---------------------------------------------------------------------------
void __fastcall TSrvCrateImage::ServiceStop(TService *Sender, bool &Stopped) {
if (MyImporter) {
MyImporter->Terminate();
HANDLE h = (HANDLE) MyImporter->Handle;
while (WaitForSingleObject(h, WaitHint-100) == WAIT_TIMEOUT) {
ReportStatus();
}
delete MyImporter;
}
Stopped = true;
}
Importer:
__fastcall Importer::Importer(bool CreateSuspended, TRegConfigFile *ConfFile)
: TThread(CreateSuspended) {
m_ConfFile = ConfFile;
m_SleepMin = ...; // read from m_ConfFile as needed
...
}
//---------------------------------------------------------------------------
__fastcall Importer::~Importer() {
delete m_ConfFile;
}
//---------------------------------------------------------------------------
void __fastcall Importer::Execute() {
while (!Terminated) {
ImportImageFiles();
Sleep(m_SleepMin * 60 * 1000);
}
}
//---------------------------------------------------------------------------
void __fastcall Importer::DoTerminate() {
if (FatalException) {
SrvCrateImage->LogMessage("Importer " + ((Exception*)FatalException)->ToString(), EVENTLOG_ERROR_TYPE);
}
TThread::DoTerminate();
}
Upvotes: 1