Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Усовершенствование программы, критика и поиск ошибок 
:(
    Опции темы
Bima
Дата 11.4.2007, 07:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Есть программа, которая читает данные по протоколу SNMP (компонент Indy: TIdSNMP) и передает эти данные в SCADA систему WinCC через DLL.
Программа работает стабильно (текущий вариант), но меня смущает то, что за пару месяцев работы, память занимаемая программой увеличивается и если программу свернуть и потом развернуть, то память сбрасывается, но потом по новой возрастает. Один раз было так, что на сервере выскочило сообщение, что вся виртуальная память занята.

Хочу дороботать программу, что бы она работала стабильнее, поэтому спрашиваю совета у ВАС. Принимается любая критика.

код программы:

модуль kod.cpp:
Код

#define ThTimOut 500  // не более 800
//---------------------------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#include <exception>

#include "inifiles.hpp"  //обязательно подключить для ини-файлов
#pragma hdrstop

#include "kod.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdSNMP"
#pragma link "CSPIN"
#pragma resource "*.dfm"
TForm1 *Form1;
int i;            //переменная цикла
int dRows;        //количество параметров
int NumPotok;     //количество потоков
int dText;        //Количество текстовых параметров
int RetStatus;    //Возвращаемое занчение статуса проекта WinCC
TIdSNMP *MySNMP[100];  //Компоненты SNMP, 100 - Это ограничение, за которое я врятли выйду
CRITICAL_SECTION OutputForm;
MyThread *MyTh[100];   //Потоки
int CounterRes[100];
TBlockList* Data;      //Блок для пересылки данных в таблицу
AnsiString *sLog=new AnsiString(); //память под лог;
TIniFile *IniF;        //Ini-файл
bool FlagExit;         //Флаг выхода из программы
bool DLL_Loaded;       //Флаг загрузки DLL
bool Connect;          //Флаг соединения с SCADA

//Объявляем указатели на массивы, память выделяем в подпрограмме ReadIniFile
AnsiString *IP;
AnsiString *Description;
AnsiString *NameTag;
AnsiString *MyTag;
AnsiString *OID;

bool *EnabledP;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
FlagExit=false;
InitializeCriticalSection(&OutputForm);
InitializeCriticalSection(&ThrCritSect);
ReadIniFile();       // Чтение ini-файла
Data = new TBlockList();
for (i=0; i<NumPotok; i++)
   {
   MySNMP[i]=new TIdSNMP(this);
   MySNMP[i]->Query->Clear();
   MySNMP[i]->Active=true;
   MySNMP[i]->BroadcastEnabled=false;
   MySNMP[i]->BufferSize=65536;
   MySNMP[i]->Community="public";
   MySNMP[i]->Port=161;
   MySNMP[i]->ReceiveTimeout=ThTimOut;
   MySNMP[i]->TrapPort=162;
   MySNMP[i]->Query ->PDUType=PDUGetRequest;
   MySNMP[i]->Name="MySNMP"+IntToStr(i);
   for (int j=0; j<dRows-3; j++)
      MySNMP[i]->Query->MIBAdd(OID[j],"");    //OID
   }
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
FlagExit=true;
for (int i=0; i<NumPotok; i++)   //убиваем потоки
   MyTh[i]->FreeOnTerminate;

Sleep(1000);  //Задержка, что бы завершились все потоки

for (i=0; i<NumPotok; i++)   //убиваем потоки
   MyTh[i]->TerminateThread();
   
for (i=0; i<NumPotok; i++)   //Убиваем компоненты SNMP
   if (MySNMP[i]!=NULL) delete MySNMP[i];

if (DLL_Loaded) FreeDLL();

if (IP != NULL) delete[] IP;
if (Description != NULL) delete[] Description;
if (NameTag != NULL) delete[] NameTag;
if (EnabledP != NULL) delete[] EnabledP;
if (MyTag != NULL) delete[] MyTag;
if (OID != NULL) delete[] OID;

DeleteCriticalSection(&OutputForm);
DeleteCriticalSection(&ThrCritSect);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormActivate(TObject *Sender)
{
//формирование шапки лога
NameLog();
FILE *f = fopen(MyNameLog.c_str(), "at");
if (!f)
   {
   Application->MessageBox("Не могу открыть файл Log.log","Error",MB_ICONSTOP);
   Close();
   }
fprintf(f, "***************************************************\n");
fprintf(f, "Start Program %s\n",DateToStr(Date()));
fprintf(f, "***************************************************\n");
fclose(f);
//конец формирования шапки лога
GridSt->ColCount=dRows+1;
GridSt->RowCount=NumPotok+1;
GridSt->Cells[0][0]=" Компьютер";
for (i=0; i<dRows; i++)
   GridSt->Cells[i+1][0] =MyTag[i] ;

for (i=0; i<NumPotok; i++)
   {
   GridSt->Cells[0][i+1]=" "+IP[i]+" ("+Description[i]+")";
   Data->PutData(IP[i],i,dRows-3); // dRows-3 это столбец с IP
   Data->PutData(Description[i],i,dRows-2); // dRows-2 это столбец с Description
   Data->PutData((EnabledP[i])?"On":"Off",i,dRows-1); // dRows-1 это столбец с Enabled
   CounterRes[i]=0;
   }

Potok();  // Подпрограмма потока

if (FlagExit) Close(); //Выход, если не удалось инициализироваться в начале

LoadDLL();  //Загрузка DLL
if (!DLL_Loaded) Close();

int Ret=WinCC_Connect();   //Соединение со SCADA
if (Ret!=OK)
   {
   if (Ret==DM_DLL_NOT_FOUND)
      Application->MessageBox("Библиотека DMClient не может быть найдена","Ошибка",MB_ICONWARNING);
   else
      Application->MessageBox("Соединение с WinCC не может быть установленно","Ошибка",MB_ICONWARNING);
   Connect=false;
   }
else
   Connect=true;

AnsiString WNameTag;
if (Connect) Ret=ProjectStatus();  // функция позволяет отследить ТОЛЬКО остановку проекта, т.е. при запуске программы вы не сможете узнать запущен ли проект
if (Ret==0)
   {
   for (i=0; i<NumPotok; i++)
      {
      WNameTag=NameTag[i]+"."+MyTag[dRows-3];   //dRows-1 это запись Tag.IP
      WriteTag_Text(WNameTag.c_str(), IP[i].c_str());
      WNameTag=NameTag[i]+"."+MyTag[dRows-2];   //dRows-1 это запись Tag.Description
      WriteTag_Text(WNameTag.c_str(), Description[i].c_str());
      }
   }

TimTimer(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
TimTimer(Sender);
Tim->Enabled=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Tim->Enabled=false;
Sleep(Tim->Interval);
Form1->SaveLog("---------------------------------");   // Log-файл
Form1->SaveLog("-      Restart Programm         -");   // Log-файл
Form1->SaveLog("---------------------------------");   // Log-файл
for (i=0; i<NumPotok; i++)
   {
   MyTh[i]->Restart=true;
   MyTh[i]->FlagQuit=true;
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CSpinEdit1Change(TObject *Sender)
{
Tim->Interval=1000*CSpinEdit1->Value;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimTimer(TObject *Sender)
{
if (FlagExit) return; //Если закрываем программу, то выход

if (Connect) RetStatus=ProjectStatus();
try{
   if (RetStatus==0)
      {
      NameLog();//Проверяем время и делаем название лога файла.
      SaveLog("---------------------------------");   // Log-файл
      for (i=0; i<NumPotok; i++)
         {
         if (!MyTh[i]->FlagQuit)
            {
            MyTh[i]->FlagQuit=true; //Если поток завершился, то запускаем его
            MyTh[i]->Resume();
            }
         else
            {
            CounterRes[i]++; //делаем задержку
            if (CounterRes[i]>1)
               {
               SaveLog("Start Restart "+IntToStr(i));   // Log-файл
               MyTh[i]->NumThread=i;
               MyTh[i]->Restart=true;
               MyTh[i]->FlagQuit=true;
               CounterRes[i]=0;
               MyTh[i]->Resume();
               }
            else
               SaveLog("Sleep "+IntToStr(i)+" <");   // Log-файл
            }
         }
      Label1->Caption = TimeToStr(Now());
      }
   else
      SaveLog("WinCC Deactivation !!!");   // Log-файл
   }
catch(...)
   {
   SaveLog("Error Timer");   // Log-файл
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SaveLog (AnsiString Stroka)
{
EnterCriticalSection(&OutputForm);
try{
    try {
        //*sLog = Now().FormatString("dd.mm.yy hh:nn:ss.zzz  ");
        *sLog = Now().FormatString("hh:nn:ss.zzz  ");
        *sLog += Stroka;
        FILE *f = fopen(MyNameLog.c_str(), "at");
        if (!f) return;
        fprintf(f, "%s\n", sLog->c_str());
        fclose(f);
        }
   catch(std::exception ex)
      {
      Application->MessageBox("Error Memory","Error",MB_ICONSTOP);
      }
    }
__finally {
  LeaveCriticalSection(&OutputForm);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Potok(void)
{
for (i=0; i<NumPotok; i++)
   {
   try{
      MyTh[i] = new MyThread(false);  //создаем поток
      MyTh[i]->FreeOnTerminate=true;
      MyTh[i]->NumThread=i; //передаем в поток переменную номер
      MyTh[i]->Restart=false; //нет перзапуска
      MyTh[i]->Resume();
      }
   catch(std::exception ex)
      {
      SaveLog("Thread "+IntToStr(i)+" no create!!!");   // Log-файл
      }
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ReadIniFile(void)         // Подпрограмма чтения ini-файла
{
IniF = new TIniFile(ChangeFileExt(ParamStr(0), ".ini"));
if (IniF==NULL)
   {
   ShowMessage("Не могу открыть INI-файл");
   return;
   }
if (!IniF->SectionExists("Global"))
   {
   ShowMessage("Нет секции ""Global"" в ini-файле");
   delete IniF;
   return;
   }
if (!IniF->SectionExists("Global"))
   {
   ShowMessage("Нет секции ""Global"" в ini-файле");
   delete IniF;
   return;
   }
if (!IniF->SectionExists("IP adress"))
   {
   ShowMessage("Нет секции ""IP adress"" в ini-файле");
   delete IniF;
   return;
   }
if (!IniF->SectionExists("Name Tag"))
   {
   ShowMessage("Нет секции ""Name Tag"" в ini-файле");
   delete IniF;
   return;
   }
if (!IniF->SectionExists("Expansion Tag"))
   {
   ShowMessage("Нет секции ""Expansion Tag"" в ini-файле");
   delete IniF;
   return;
   }
if (!IniF->SectionExists("OID"))
   {
   ShowMessage("Нет секции ""OID"" в ini-файле");
   delete IniF;
   return;
   }
dRows = IniF->ReadInteger("Global", "dRows",1);
NumPotok = IniF->ReadInteger("Global", "dCols",1);
dText = IniF->ReadInteger("Global", "dText",1);
dRows=dRows+3;  //Здесь мы прибавляем информацию в таблицу (IP, Description, Enabled)

//выделяем память под массивы
try {
   IP = new AnsiString[NumPotok];
   Description = new AnsiString[NumPotok];
   NameTag = new AnsiString[NumPotok];
   EnabledP = new bool[NumPotok];
   MyTag = new AnsiString[dRows];
   OID = new AnsiString[dRows];
   }
catch (std::exception ex)
   {
   FlagExit=true;
   Application->MessageBox("Error Memory","Error",MB_ICONSTOP);
   return;
   }

for (i=0; i<NumPotok; i++)
   {
   IP[i]=IniF->ReadString("IP adress", "System"+IntToStr(i+1), "0.0.0.0");
   NameTag[i]=IniF->ReadString("Name Tag", "System"+IntToStr(i+1), "Name Tag");
   Description[i]=IniF->ReadString("Description", "System"+IntToStr(i+1), "Description");
   EnabledP[i]=true;
   }

for (i=0; i<dRows-3; i++)
   {
   MyTag[i]=IniF->ReadString("Expansion Tag", "Param"+IntToStr(i+1), "Expansion Tag");
   OID[i]=IniF->ReadString("OID", "Param"+IntToStr(i+1), "OID");
   }
MyTag[dRows-3]="IP";
MyTag[dRows-2]="Description";
MyTag[dRows-1]="Enabled";

delete IniF;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::NameLog(void)
{
EnterCriticalSection(&OutputForm);
try{
   TDateTime dtTime = Now();
   DecodeTime(dtTime, Hour, Minut, Sec, MSec);
   if (Hour!=OldHour)
      {
      DecodeDate(dtTime, Year, Month, Day);
      MyNameLog="Log("+IntToStr(Year)+"_"+IntToStr(Month)+"_"+IntToStr(Day)+" "+IntToStr(Hour)+").log";
      OldHour=Hour;
      }
   }
__finally {
  LeaveCriticalSection(&OutputForm);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnWM_END_THREAD(TMessage& Msg)
{
try{
   Label3->Caption=TimeToStr(Now())+"  Thread("+IntToStr((long)Msg.LParam)+")";
   }
catch(...)
   {
   SaveLog("Error WM_END_THREAD");   // Log-файл
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OnWM_UPDATE_GRID(TMessage& Msg)
{
try{
   long GridRow = (long)Msg.LParam;

   for (i=0; i<dRows; i++)
      GridSt->Cells[i+1][GridRow+1]=Data->GetData(GridRow,i);
   }
catch(...)
   {
   SaveLog("Error WM_UPDATE_GRID");   // Log-файл
   return;
   }
}
//---------------------------------------------------------------------------












//блок передачи данных в таблицу
//---------------------------------------------------------------------------
int num;
__fastcall TBlockList::TBlockList():TStringList()
{
busy = new TCriticalSection();
for (int i=0; i<dRows; i++)
   {
   for (int k=0; k<NumPotok; k++)
      Add("                                                  ");  //инициализация начальных параметров
   }
}
//---------------------------------------------------------------------------
__fastcall TBlockList::~TBlockList() { delete busy; }
//---------------------------------------------------------------------------
void __fastcall TBlockList::PutData(const AnsiString item, int col, int row)
{
busy->Enter();
try {
    num=col*dRows+row;
    Strings[num]=item;
    }
__finally { busy->Leave(); }
}
//---------------------------------------------------------------------------
AnsiString __fastcall TBlockList::GetData(int col, int row)
{
busy->Enter();
AnsiString ret="";
try {
    num=col*dRows+row;
    ret=Get(num);
    }
__finally { busy->Leave(); }
return ret;
}
//---------------------------------------------------------------------------





//поток
CRITICAL_SECTION ThrCritSect;
//---------------------------------------------------------------------------
__fastcall MyThread::MyThread(bool CreateSuspended):TThread(CreateSuspended){};
//---------------------------------------------------------------------------
void __fastcall MyThread::Execute()
{
while (!Terminated)
   {
   while (FlagQuit)
      {
      if (Restart)
         HotRestart(true);
      else
         {
         FlagQuit = false;
         FreeOnTerminate=true;
         ThReadFlag();      //
         ThSendQuery();     //
         FlagExec=true;     //показывает, что в функцию ThReadQuery, мы зашли из Execute
         }
      Suspend();
      }
   Sleep(1);//нужно, что бы небыло 100% загрузки CPU и переключения на другие задачи.
   }
}
//---------------------------------------------------------------------------
void __fastcall MyThread::ThReadFlag()
{
try{
   WNameTag=NameTag[NumThread]+"."+MyTag[dRows-1];   //dRows-1 это запись Tag.Enabled
   EnterCriticalSection(&ThrCritSect);
   try{
      EnabledP[NumThread]=ReadTag_Boolean(WNameTag.c_str());
      }
   __finally {LeaveCriticalSection(&ThrCritSect);}
   Data->PutData((EnabledP[NumThread])?"On":"Off",NumThread,dRows-1); // dRows-1 это столбец с Enabled
   }
catch(...)
   {
   Form1->SaveLog("ReadFlag Error ("+IntToStr(NumThread)+ ") -- < ! > --");   // Log-файл
   }
}
//---------------------------------------------------------------------------
void __fastcall MyThread::ThSendQuery()
{//  Эта подпрограмма НЕ должна быть синхронизирована
Form1->SaveLog("SendQuery("+IntToStr(NumThread)+ ")");   // Log-файл
MySNMP[NumThread]->Query->Clear();
MySNMP[NumThread]->Query->Host=IP[NumThread];
MySNMP[NumThread]->Community="public";
MySNMP[NumThread]->Query ->PDUType=PDUGetRequest;
// **************** можно весь блок заремировать **************
for (i=0; i<dRows-3; i++)
   MySNMP[NumThread]->Query->MIBAdd(OID[i],"");    //OID
//*************************************************************
MySNMP[NumThread]->Reply->Clear();
try{
   MySNMP[NumThread]->SendQuery();
   }
catch(...)
   {
   Form1->SaveLog("SendQuery Error ("+IntToStr(NumThread)+ ") -- < ! > --");   // Log-файл
   return;
   }
Sleep(1);
ThReadQuery();
}
//---------------------------------------------------------------------------
void __fastcall MyThread::ThReadQuery()
{//  Эта подпрограмма НЕ должна быть синхронизирована
try{
   EndCycle=MySNMP[NumThread]->Reply->ValueCount;
   Form1->SaveLog("ReadQuery ("+IntToStr(NumThread)+ ")");   // Log-файл
   if (EndCycle!=dRows-3)
      {
      Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- ValueCount ("+IntToStr(EndCycle)+")");   // Log-файл
      //Debug***************
      Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- Community ("+MySNMP[NumThread]->Community +")");   // Log-файл
      Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- BufferSize ("+IntToStr(MySNMP[NumThread]->BufferSize)+")");   // Log-файл
      if (MySNMP[NumThread]->Active)
         Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- Active = true");   // Log-файл
      else
         Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- Active = false");   // Log-файл
      if (MySNMP[NumThread]->BroadcastEnabled)
         Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- BroadcastEnabled = true");   // Log-файл
      else
         Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") -- < !!! > -- BroadcastEnabled = false");   // Log-файл
      //********************
      return;
      }
   for (i=0; i<EndCycle-dText; i++) //передача числовых значений
      {
      Data->PutData(MySNMP[NumThread]->Reply->Value[i], NumThread, i);
      WNameTag=NameTag[NumThread]+"."+MyTag[i];
      if (EnabledP[NumThread])
         {
         EnterCriticalSection(&ThrCritSect);
         try{
            if (Digit(MySNMP[NumThread]->Reply->Value[i]))
               WriteTag_Word(WNameTag.c_str(), StrToInt(MySNMP[NumThread]->Reply->Value[i]));
            else
               Form1->SaveLog("Error WriteTag_Word("+IntToStr(NumThread)+ ") Tag="+WNameTag);   // Log-файл
            }
         __finally {LeaveCriticalSection(&ThrCritSect);}
         }
      }
   for (i=0; i<dText; i++)  //передача текстовых значений
      {
      iText=EndCycle-dText+i;
      Data->PutData(MySNMP[NumThread]->Reply->Value[iText], NumThread, iText);
      WNameTag=NameTag[NumThread]+"."+MyTag[iText];
      if (EnabledP[NumThread])
         {
         EnterCriticalSection(&ThrCritSect);
         try{
            if (MySNMP[NumThread]->Reply->Value[iText].Length()<128)//можно поставить 255
               WriteTag_Text(WNameTag.c_str(), MySNMP[NumThread]->Reply->Value[iText].c_str());
            else
               Form1->SaveLog("Error WriteTag_Text("+IntToStr(NumThread)+ ") (Length>128) Tag="+WNameTag);   // Log-файл
            }
         __finally {LeaveCriticalSection(&ThrCritSect);}
         }
      }
   PostMessage(Form1->Handle, WM_UPDATE_GRID, 0, (long)NumThread);
   }
catch(...)
   {
   Form1->SaveLog("Error Read("+IntToStr(NumThread)+ ") Exception -- < !!! > --");   // Log-файл
   return;
   }
}
//---------------------------------------------------------------------------
bool __fastcall MyThread::TerminateThread(void)
{
Suspend();
return ::TerminateThread((void*)Handle, 0);
}
//---------------------------------------------------------------------------
void __fastcall MyThread::HotRestart(bool Log)
{//  Эта подпрограмма должна быть синхронизирована
if (!Restart) return;
try{
   Restart=false;
   Sleep(ThTimOut);//Ждем завершение потока.
   if (Log) Form1->SaveLog("HotRestart ("+IntToStr(NumThread)+ ")----<!!!!!!!!!!!!!!!>----");   // Log-файл
   MySNMP[NumThread]->Query->Clear();
   MySNMP[NumThread]->Active=false;
   MySNMP[NumThread]->Active=true;
   MySNMP[NumThread]->BroadcastEnabled=true;
   MySNMP[NumThread]->BroadcastEnabled=false;
   MySNMP[NumThread]->BufferSize=65536;
   MySNMP[NumThread]->Community="public";
   MySNMP[NumThread]->Port=161;
   MySNMP[NumThread]->ReceiveTimeout=ThTimOut;
   MySNMP[NumThread]->TrapPort=162;
   MySNMP[NumThread]->Query ->PDUType=PDUGetRequest;
   MySNMP[NumThread]->Name="MySNMP"+IntToStr(i);
   for (i=0; i<dRows-3; i++)
      MySNMP[NumThread]->Query->MIBAdd(OID[i],"");    //OID
   MySNMP[NumThread]->Reply->Clear();
   FlagQuit = false;
   }
catch(...)
   {
   FlagQuit = false;
   Form1->SaveLog("HotRestart Error ("+IntToStr(NumThread)+ ") -- < ! > --");   // Log-файл
   return;
   }
}
//---------------------------------------------------------------------------
bool __fastcall MyThread::Digit (AnsiString Cifra)
{
try
    {
    StrToFloat(Cifra);
    return true;
    }
catch(...)//Выполняется в случае ошибки
    {
    return false;
    }
}
//---------------------------------------------------------------------------









//---------------------------------------------------------------------------
HINSTANCE dllinstance;
//******************************************************
pWinCC_Connect *WinCC_Connect;
pWinCC_Disconnect *WinCC_Disconnect;
pProjectStatus *ProjectStatus;
//******************************************************
pReadTag_Boolean  *ReadTag_Boolean;
pReadTag_Byte *ReadTag_Byte;
pReadTag_Word *ReadTag_Word;
pReadTag_Integer *ReadTag_Integer;
pReadTag_Integer64 *ReadTag_Integer64;
pReadTag_Real32 *ReadTag_Real32;
pReadTag_Real64 *ReadTag_Real64;
pReadTag_Text *ReadTag_Text;
//******************************************************
pReadTag_BoolArray *ReadTag_BoolArray;
pReadTag_RealArray32 *ReadTag_RealArray32;
//******************************************************
pWriteTag_Integer *WriteTag_Integer;
pWriteTag_Word *WriteTag_Word;
pWriteTag_Word64 *WriteTag_Word64;
pWriteTag_Real *WriteTag_Real;
pWriteTag_Text *WriteTag_Text;
//******************************************************
pWriteTag_BoolArray *WriteTag_BoolArray;
pWriteTag_RealArray *WriteTag_RealArray;
//---------------------------------------------------------------------------
void LoadDLL(void)
{
DLL_Loaded=false;
dllinstance = LoadLibrary("ODK_RW_Tags.dll");
if(!dllinstance) // если dll не была загружена
   {
   MessageBox(0,"Не могу найти ODK_RW_Tags.dll. Она должна где-то быть!","Ошибка",MB_ICONWARNING);
   return;
   }
else
   {
   //***********
   WinCC_Connect = (pWinCC_Connect*)GetProcAddress(dllinstance,"WinCC_Connect");
   assert(WinCC_Connect != NULL);
   WinCC_Disconnect = (pWinCC_Disconnect*)GetProcAddress(dllinstance,"WinCC_Disconnect");
   assert(WinCC_Disconnect != NULL);
   ProjectStatus = (pProjectStatus*)GetProcAddress(dllinstance,"ProjectStatus");
   assert(ProjectStatus != NULL);
   //***********
   ReadTag_Boolean = (pReadTag_Boolean*)GetProcAddress(dllinstance,"ReadTag_Boolean");
   assert(ReadTag_Boolean != NULL);
   ReadTag_Byte = (pReadTag_Byte*)GetProcAddress(dllinstance,"ReadTag_Byte");
   assert(ReadTag_Byte != NULL);
   ReadTag_Word = (pReadTag_Word*)GetProcAddress(dllinstance,"ReadTag_Word");
   assert(ReadTag_Word != NULL);
   ReadTag_Integer = (pReadTag_Integer*)GetProcAddress(dllinstance,"ReadTag_Integer");
   assert(ReadTag_Integer != NULL);
   ReadTag_Integer64 = (pReadTag_Integer64*)GetProcAddress(dllinstance,"ReadTag_Integer64");
   assert(ReadTag_Integer64 != NULL);
   ReadTag_Real32 = (pReadTag_Real32*)GetProcAddress(dllinstance,"ReadTag_Real32");
   assert(ReadTag_Real32 != NULL);
   ReadTag_Real64 = (pReadTag_Real64*)GetProcAddress(dllinstance,"ReadTag_Real64");
   assert(ReadTag_Real64 != NULL);
   ReadTag_Text = (pReadTag_Text*)GetProcAddress(dllinstance,"ReadTag_Text");
   assert(ReadTag_Text != NULL);
   //***********
   ReadTag_BoolArray = (pReadTag_BoolArray*)GetProcAddress(dllinstance,"ReadTag_BoolArray");
   assert(ReadTag_BoolArray != NULL);
   ReadTag_RealArray32 = (pReadTag_RealArray32*)GetProcAddress(dllinstance,"ReadTag_RealArray32");
   assert(ReadTag_RealArray32 != NULL);
   //***********
   WriteTag_Integer = (pWriteTag_Integer*)GetProcAddress(dllinstance,"WriteTag_Integer");
   assert(WriteTag_Integer != NULL);
   WriteTag_Word = (pWriteTag_Word*)GetProcAddress(dllinstance,"WriteTag_Word");
   assert(WriteTag_Word != NULL);
   WriteTag_Word64 = (pWriteTag_Word64*)GetProcAddress(dllinstance,"WriteTag_Word64");
   assert(WriteTag_Word64 != NULL);
   WriteTag_Real = (pWriteTag_Real*)GetProcAddress(dllinstance,"WriteTag_Real");
   assert(WriteTag_Real != NULL);
   WriteTag_Text = (pWriteTag_Text*)GetProcAddress(dllinstance,"WriteTag_Text");
   assert(WriteTag_Text != NULL);
   //***********
   WriteTag_BoolArray = (pWriteTag_BoolArray*)GetProcAddress(dllinstance,"WriteTag_BoolArray");
   assert(WriteTag_BoolArray != NULL);
   WriteTag_RealArray = (pWriteTag_RealArray*)GetProcAddress(dllinstance,"WriteTag_RealArray");
   assert(WriteTag_RealArray != NULL);
   //***********
   DLL_Loaded=true;
   }
}
//---------------------------------------------------------------------------
void FreeDLL(void)
{
FreeLibrary(dllinstance);
}
//---------------------------------------------------------------------------
void WriteTag_Boolean(char *TagName, bool value)
{
if (value) WriteTag_Integer(TagName, 1);
else WriteTag_Integer(TagName, 0);
}
//---------------------------------------------------------------------------


Могу пояснить любой участок кода, так как сам писал программу.
Заранее спасибо за советы


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
Bima
Дата 11.4.2007, 07:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



в первом сообщении не поместился Модуль kod.h:
Код

//---------------------------------------------------------------------------
#ifndef kodH
#define kodH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <SyncObjs.hpp>
#include "IdSNMP.hpp"
#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdUDPBase.hpp>
#include <IdUDPClient.hpp>
#include <Grids.hpp>
#include <windows.h>
#include <assert.h>
#include "CSPIN.h"
#include <IdAntiFreeze.hpp>
#include <IdAntiFreezeBase.hpp>

AnsiString MyNameLog;   // название лога программы
Word Year, Month, Day, Hour, Minut, Sec, MSec;
Word OldHour;

const WM_END_THREAD = WM_USER + 101;
const WM_UPDATE_GRID = WM_USER + 102;
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
   TTimer *Tim;
   TIdSNMP *IdSNMP1;
   TButton *Button2;
   TLabel *Label1;
   TStringGrid *GridSt;
   TLabel *Label2;
   TLabel *Label3;
   TButton *Button1;
   TCSpinEdit *CSpinEdit1;
   TIdAntiFreeze *IdAntiFreeze1;
   void __fastcall FormActivate(TObject *Sender);
   void __fastcall TimTimer(TObject *Sender);
   void __fastcall Button2Click(TObject *Sender);
   void __fastcall Button1Click(TObject *Sender);
   void __fastcall CSpinEdit1Change(TObject *Sender);
private:    // User declarations
public:        // User declarations
   __fastcall TForm1(TComponent* Owner);
   __fastcall virtual ~TForm1(void);
  void __fastcall SaveLog (AnsiString Stroka);
  void __fastcall Potok(void);               // Подпрограмма потока
  void __fastcall ReadIniFile(void);         // Подпрограмма чтения ini-файла
  void __fastcall NameLog(void);             // Формирование название лога программы
  void __fastcall OnWM_END_THREAD(TMessage& Msg);
  void __fastcall OnWM_UPDATE_GRID(TMessage& Msg);
protected:
#pragma warn -8027   //Чтобы не выдавалось предупреждения w8027
  BEGIN_MESSAGE_MAP
          VCL_MESSAGE_HANDLER(WM_END_THREAD, TMessage, OnWM_END_THREAD)
          VCL_MESSAGE_HANDLER(WM_UPDATE_GRID, TMessage, OnWM_UPDATE_GRID)
  END_MESSAGE_MAP(TForm)

};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
class TBlockList : protected TStringList
{
  TCriticalSection *busy;
public:
  __fastcall TBlockList();
  virtual __fastcall ~TBlockList();
  void __fastcall PutData(const AnsiString item, int col, int row);
  AnsiString __fastcall GetData(int col, int row);
};
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
class MyThread : public TThread
{            
private:
protected:
   void __fastcall Execute();
   bool FlagSend;
   bool FlagExec;
   AnsiString WNameTag;
   int EndCycle;
   int i;// переменная цикла
   int iText;
public:
   __fastcall MyThread(bool CreateSuspended);
   void __fastcall ThReadFlag();    //Чтения флагов с WinCC
   void __fastcall ThSendQuery();   //
   void __fastcall ThReadQuery();   //
   bool __fastcall TerminateThread(void);
   void __fastcall HotRestart(bool Log);
   bool __fastcall Digit (AnsiString Cifra);
   bool FlagQuit;
   int NumThread;
   bool Restart;
};
extern CRITICAL_SECTION ThrCritSect;
//extern CRITICAL_SECTION ThrCritSectW;
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
const OK = 0;
const DM_CONNECT_FAILED = 1;
const DM_DLL_NOT_FOUND  = 2;

//extern HINSTANCE dllinstance;
//******************************************************
// коннект, дисконект и статус
typedef int __declspec (dllimport) pWinCC_Connect(void);
extern pWinCC_Connect *WinCC_Connect;
typedef int __declspec (dllimport) pWinCC_Disconnect(void);
extern pWinCC_Disconnect *WinCC_Disconnect;
typedef int __declspec (dllimport) pProjectStatus(void);
extern pProjectStatus *ProjectStatus;
//******************************************************
// функции чтения
typedef bool __declspec (dllimport) pReadTag_Boolean (char * TagName);
extern pReadTag_Boolean  *ReadTag_Boolean;
typedef int __declspec (dllimport) pReadTag_Byte (char * TagName);
extern pReadTag_Byte *ReadTag_Byte;
typedef long __declspec (dllimport) pReadTag_Word (char * TagName);
extern pReadTag_Word *ReadTag_Word;
typedef long __declspec (dllimport) pReadTag_Integer (char * TagName);
extern pReadTag_Integer *ReadTag_Integer;
typedef long __declspec (dllimport) pReadTag_Integer64 (char * TagName);
extern pReadTag_Integer64 *ReadTag_Integer64;
typedef float __declspec (dllimport) pReadTag_Real32 (char * TagName);
extern pReadTag_Real32 *ReadTag_Real32;
typedef double __declspec (dllimport) pReadTag_Real64 (char * TagName);
extern pReadTag_Real64 *ReadTag_Real64;
typedef void __declspec (dllimport) pReadTag_Text (char * TagName, char* value[255]);
extern pReadTag_Text *ReadTag_Text;
//******************************************************
// для чтения значений у группы тегов, в вызывающей программе должны быть
// заведены массивы соотвествующих типов
typedef void __declspec (dllimport) pReadTag_BoolArray (char *TagNames, bool *value, int count);
extern pReadTag_BoolArray *ReadTag_BoolArray;
typedef void __declspec (dllimport) pReadTag_RealArray32 (char *TagNames, double *value);
extern pReadTag_RealArray32 *ReadTag_RealArray32;
//******************************************************
// функции записи
typedef void __declspec (dllimport) pWriteTag_Integer(char *TagName, int value);
extern pWriteTag_Integer *WriteTag_Integer;
typedef void __declspec (dllimport) pWriteTag_Word (char *TagName, long value);
extern pWriteTag_Word *WriteTag_Word;
typedef void __declspec (dllimport) pWriteTag_Word64 (char *TagName, unsigned long value);
extern pWriteTag_Word64 *WriteTag_Word64;
typedef void __declspec (dllimport) pWriteTag_Real(char *TagName, double value);
extern pWriteTag_Real *WriteTag_Real;
typedef void __declspec (dllimport) pWriteTag_Text (char *TagName, char* value);
extern pWriteTag_Text *WriteTag_Text;
//******************************************************
// функции записи групповых тегов
typedef void __declspec (dllimport) pWriteTag_BoolArray (char *TagNames, bool* value, int count);
extern pWriteTag_BoolArray *WriteTag_BoolArray;
typedef void __declspec (dllimport) pWriteTag_RealArray (char *TagNames, double* value);
extern pWriteTag_RealArray *WriteTag_RealArray;
//******************************************************

// функции
void LoadDLL(void);
void FreeDLL(void);
void WriteTag_Boolean(char *TagName, bool value);
//---------------------------------------------------------------------------
#endif



--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
pandrew
Дата 11.4.2007, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 213
Регистрация: 27.3.2006

Репутация: 3
Всего: 3



Кто же будет разбираться в чужом хламе такого размера? smile 
Установи BoundsChecker или что-нибудь подобное и следи за утечками.
PM MAIL   Вверх
ama_kid
Дата 11.4.2007, 09:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 10
Всего: 95



Bima
Хм... Я думаю, ты и сам понимаешь, что на таком коде сложно делать визуальную отладку. Было бы, конечно, лучше, чтобы ты прикрепил целиком проект с библиотекой (у меня, допустим, WinCC нет, я работаю с другими SCADA). Но вот так навскидку вопрос: почему у тебя в Form1Activate делается такая куча действий? К примеру каждый раз при активации формы у тебя загружается библиотека, каждый раз запускается функция Potok(); создающая потоки каждый раз. В общем, я не совсем это понимаю...

Ну и по мелочам:
1) Вот этот код я не понял:
Код
for (int i=0; i<NumPotok; i++)   //убиваем потоки
   MyTh[i]->FreeOnTerminate;

Sleep(1000);  //Задержка, что бы завершились все потоки

for (i=0; i<NumPotok; i++)   //убиваем потоки
   MyTh[i]->TerminateThread();

Первый цикл вообще бесполезный ибо не убивает потоки. FreeOnTerminate - это свойство, указывающее на возможность автоматического освобождения ресурсов при завершении потока. Следовательно, Sleep бесполезен, лучше его поставить после второго цикла, а первый вообще убрать. А еще лучше использовать не Sleep, а WaitForSingleObject или WaitForMultipleObjects
2) Вот здесь (при создании потоков):
Код

   try{
      MyTh[i] = new MyThread(false);  //создаем поток
      MyTh[i]->FreeOnTerminate=true;
      MyTh[i]->NumThread=i; //передаем в поток переменную номер
      MyTh[i]->Restart=false; //нет перзапуска
      MyTh[i]->Resume();
      }
   catch(std::exception ex)
      {
      SaveLog("Thread "+IntToStr(i)+" no create!!!");   // Log-файл
      }
ты создаешь поток с параметром false (т.е. поток идет сразу на запуск), пытаешься задать ему какие-то параметры, а потом пытаешься сделать ему Resume()... А вдруг он уже к тому моменту завершился? Вряд ли, конечно, но все-таки имхо лучше создавать с CreateSuspended = true...

Ну и, думаю, если серьезно покопать, можно найти еще несколько не совсем корректных действий, приводящих к возможным утечкам памяти... Но опять же - визуально это достаточно сложно сделать...


--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Bima
Дата 11.4.2007, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



for pandrew
Я вообще предлагал другое, не разбираться в моей программе, а показать, как можно сделать некоторые участки кода по другому. Я практически уверен, что большинство кода, который написан выше - неоптимальный.
Утечки памяти пробовал отслеживать на CodeGuard, но мне там не совсем понятно, как и что отслеживается.

По поводу "такого размера"... если писать код кусками в каждой новой теме, то не всегда понятен смысл всей программы, да и оптимизация будет только на уровне блока, а не на уровне всей программы. Этот вариант уже проходил, так как многие куски кода, которые используются в этой программе, взяты именно с ответов этого форума.

for ama_kid
Цитата

К примеру каждый раз при активации формы у тебя загружается библиотека, каждый раз запускается функция Potok(); создающая потоки каждый раз. В общем, я не совсем это понимаю...

Ставил прерывание на Form1Activate, оно выполняется только один раз....
может я ошибаюсь, но помоему, оно выполняется только один раз при запуске приложения
Цитата

Первый цикл вообще бесполезный ибо не убивает потоки. FreeOnTerminate - это свойство, указывающее на возможность автоматического освобождения ресурсов при завершении потока. Следовательно, Sleep бесполезен, лучше его поставить после второго цикла, а первый вообще убрать. 

Я пытался там написать MyTh[i]->Terminate=true; , но у меня приложение при завершении выскакивало с ошибкой.
Цитата

А еще лучше использовать не Sleep, а WaitForSingleObject или WaitForMultipleObjects

Для примера, как написать завершение потоков с помощью WaitForSingleObject или WaitForMultipleObjects???
Цитата

ты создаешь поток с параметром false (т.е. поток идет сразу на запуск), пытаешься задать ему какие-то параметры, а потом пытаешься сделать ему Resume()... А вдруг он уже к тому моменту завершился? Вряд ли, конечно, но все-таки имхо лучше создавать с CreateSuspended = true...

Да здесь я ошибся, писал  на автомате, думая, что задав true, у меня сразу запустится поток. Логика у меня такая: создается поток, присваивается ему значения, а потом запускается в нужный момент.

Выкладываю весь проект здесь.

Присоединённый файл ( Кол-во скачиваний: 7 )
Присоединённый файл  Test_SNMP_WinCC9.rar 56,10 Kb


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
ama_kid
Дата 11.4.2007, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 10
Всего: 95



Цитата(Bima @  11.4.2007,  09:40 Найти цитируемый пост)
Я пытался там написать MyTh[i]->Terminate=true; , но у меня приложение при завершении выскакивало с ошибкой.
Надо писать просто MyTh[i]->Terminate(); Это функция, выдающая потоку команду завершиться (она устанавливает приватное свойство Terminated в true)...
Цитата(Bima @  11.4.2007,  09:40 Найти цитируемый пост)
может я ошибаюсь, но помоему, оно выполняется только один раз при запуске приложения
Один раз при запуске приложения выполняется OnCreate, а OnActivate выполняется каждый раз, когда форма становиться активной...
Цитата(Bima @  11.4.2007,  09:40 Найти цитируемый пост)
Для примера, как написать завершение потоков с помощью WaitForSingleObject или WaitForMultipleObjects???
Ну примерно так (пишу прямо в форум, более корректные примеры смотреть здесь):
Код

MyTh[i]->Terminate();
if (WaitForSingleObject(MyTh[i]->Handle,500)!=WAIT_OBJECT_0) ShowMessage("Поток не завершился!");

Цитата
Выкладываю весь проект здесь.
А где здесь файл формы?  (у меня Turbo C++ Builder)


--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Bima
Дата 11.4.2007, 10:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Цитата

А где здесь файл формы?  (у меня Turbo C++ Builder) 

выкладываю.
Цитата

Один раз при запуске приложения выполняется OnCreate, а OnActivate выполняется каждый раз, когда форма становиться активной...

Да, я читал про это, но на практике, сколько бы раз я ее не сворачивал разварачивал... не передавал фокус на другое окно, все равно, OnActivate выполняется только при загрузке формы.
Цитата

MyTh[i]->Terminate();
if (WaitForSingleObject(MyTh[i]->Handle,500)!=WAIT_OBJECT_0) ShowMessage("Поток не завершился!");

хм... поток не завершился, и что после этого делать.... убивать его принудительно???

Присоединённый файл ( Кол-во скачиваний: 6 )
Присоединённый файл  add.rar 1,16 Kb


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
pandrew
Дата 11.4.2007, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 213
Регистрация: 27.3.2006

Репутация: 3
Всего: 3



Цитата(Bima @  11.4.2007,  10:46 Найти цитируемый пост)
хм... поток не завершился, и что после этого делать.... убивать его принудительно??? 

Поток надо так написать, чтобы он когда-нибудь завершился. 
А так после Terminate() вызываешь WaitFor() и зануляешь указатель на поток.
Код
MyTh[i]->Terminate();
MyTh[i]->WaitFor();
MyTh[i]=0;

Тогда, по крайней мере, AV не получишь.
PM MAIL   Вверх
Bima
Дата 11.4.2007, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Цитата

Поток надо так написать, чтобы он когда-нибудь завершился.

на уровне простого програмирования (имеется ввиду внутренние объекты компьютера), выходит, что нужно так писать, но когда в потоке задействовано опрос какой нибудь внешней железки, которая может просто напросто не ответить или связь оборвется, в этом случае поток может просто напросто висеть, и завершать его все равно придется принудительно (это я пишу только для закрытия программы).

по поводу кода, я такой уже встречал здесь, там как раз ругаются на такой алгоритм.


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
pandrew
Дата 11.4.2007, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 213
Регистрация: 27.3.2006

Репутация: 3
Всего: 3



Цитата(Bima @  11.4.2007,  12:07 Найти цитируемый пост)
на уровне простого програмирования (имеется ввиду внутренние объекты компьютера), выходит, что нужно так писать, но когда в потоке задействовано опрос какой нибудь внешней железки, которая может просто напросто не ответить или связь оборвется, в этом случае поток может просто напросто висеть, и завершать его все равно придется принудительно (это я пишу только для закрытия программы).

Я работаю много лет с разными железками подключенными к ПК (RS-232, USB, TCP/IP). Поверь на слово, есть в WinAPI все функции для опроса железяк, в которых невозможно зависнуть навсегда. Проблема сводится к выбору адекватного таймаута.
А по поводу ругани и здесь было (якобы к моменту WaitFor переменная потока уже неадекватна), но у меня все годами работает в сотнях экземплярах, т.е. в этом месте проблем не встречал.
PM MAIL   Вверх
Bima
Дата 11.4.2007, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Цитата

А по поводу ругани и здесь было (якобы к моменту WaitFor переменная потока уже неадекватна), но у меня все годами работает в сотнях экземплярах, т.е. в этом месте проблем не встречал.

поробовал код:
Код

MyTh[i]->Terminate();
MyTh[i]->WaitFor();
MyTh[i]=0;

Получил висящее приложение. Окно программы закрылось, а в памяти процесс остался.
Если запускать в среде разработки ВСВ, то видно, что программа не отработала.

Пытался делать
Код

MyTh[i]->Terminate();
if (WaitForSingleObject(MyTh[i]->Handle,500)!=WAIT_OBJECT_0) ShowMessage("Поток не завершился!");

получил ошибки:
Код

[C++ Error] kod.cpp(81): E2034 Cannot convert 'const unsigned int' to 'void *'
[C++ Error] kod.cpp(81): E2342 Type mismatch in parameter 'hHandle' (wanted 'void *', got 'unsigned int')
[C++ Error] kod.cpp(560): E2096 Illegal structure operation

строка 81, это как раз строка с if


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
ama_kid
Дата 11.4.2007, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 10
Всего: 95



Цитата
получил ошибки:
(WaitForSingleObject(&(MyTh[i]->Handle),500)!=WAIT_OBJECT_0)
Цитата(Bima @  11.4.2007,  10:46 Найти цитируемый пост)
хм... поток не завершился, и что после этого делать.... убивать его принудительно???
Цитата
Получил висящее приложение. Окно программы закрылось, а в памяти процесс остался.
       Смотри на код потока - ты делаешь ему Suspend(); после этого он естественно не сможет завершиться до вызова Resume(); следовательно его хендл не будет выставлен в сигнальное состояние и WaitForSingleObject сработает по таймауту (а WaitFor() повесит приложение). Поэтому у тебя он и не завершается... Я так понял ты делаешь следующее: усыпляешь поток, при следующем твоем событии выставляешь флаг на однократное выполнение действия, запускаешь его и он, выполнив приказ, опять засыпает... В таком состоянии, как я уже сказал, ты не сможешь его завершить, поток должен крутиться постоянно (чтобы иметь возможность проверить свойство Terminated), а уже внутри этого цикла проверять флаг на определенное действие (кстати, с таким подходом идеологически больше подходит обычная функция, а не поток). А по поводу ссылки, где ругаются на код - это из-за того, что происходит как раз обращение к объекту потока, когда он уже освобожден (FreeOnTerminate = true и после команды Terminate он успевает освободится до того момента, когда вызывается WaitFor())...
       Но это все лирика, бог с ними, с самими потоками... На самом деле, мне кажется, в данном случае надо смотреть еще глубже - в функции, с которыми потоки работают... И вот тут есть самое главное замечание, которое я могу высказать - это... Хм, я лучше процитирую хелп к функции Execute объекта потока:
Цитата
Note: 
Do not use the properties and methods of other objects directly in the Execute method of a thread. Instead, separate the use of other objects into a separate procedure call, and call that procedure by passing it as a parameter to the Synchronize method.
У тебя же во всех потоках вызывается куча методов разных объектов (причем вызов - в пределах объекта потока), начиная от сетевых компонентов и заканчивая главной формой. В таких условиях я вряд ли смогу указать тебе кусок кода, который вызывает утечки памяти, мне кажется сама структура программы ведёт к этому. Если честно, я вообще удивлен, как программа у тебя работает, да еще и стабильно (мне так не удалось её запустить ввиду отсутствия компонента Indy6.0 и некоего нестандартного спинедита), а уж мемори-лики в таких условиях - имхо дело обычное... Мне кажется, нужно попробовать пересмотреть структуру приложения и сделать один поток, обслуживающий подключенных клиентов, и один поток на обмен с WinCC, т.е. разделить задачу. При этом надо уделить серьезное внимание вопросу их синхронизации и синхронизации с главной формой. Ну и, конечно, имхо такие вещи лучше делать на WinAPI...



--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Bima
Дата 11.4.2007, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Цитата

У тебя же во всех потоках вызывается куча методов разных объектов (причем вызов - в пределах объекта потока), начиная от сетевых компонентов и заканчивая главной формой. В таких условиях я вряд ли смогу указать тебе кусок кода, который вызывает утечки памяти, мне кажется сама структура программы ведёт к этому. Если честно, я вообще удивлен, как программа у тебя работает, да еще и стабильно (мне так не удалось её запустить ввиду отсутствия компонента Indy6.0 и некоего нестандартного спинедита), а уж мемори-лики в таких условиях - имхо дело обычное... Мне кажется, нужно попробовать пересмотреть структуру приложения и сделать один поток, обслуживающий подключенных клиентов, и один поток на обмен с WinCC, т.е. разделить задачу. При этом надо уделить серьезное внимание вопросу их синхронизации и синхронизации с главной формой. Ну и, конечно, имхо такие вещи лучше делать на WinAPI...

Очень конструктивная критика smile

1) в пределах объекта потока я НЕ вызываю компонеты из главной формы. Для передачи данных у меня существует блок TBlockList* Data, с критической секцией на доступ.
Для записи лог файла, я использую тоже критическую секцию, так что здесь затыков не должно быть.
2) если делать один поток и постоянно перенастраивать сетевые компонеты, то скорость сильно падает в зависимости от количества устройств. Допустим у меня есть 10 железяк с опросом в 1 секунду, если опрос нормальный, то он занимает до 100 мс, следовательно при нормальном опросе 10 устройств займет 1 сек, а если мне нужно опросить больше? Все это при нормальном опросе, а если хотя-бы пару железяк зависло, то при опросе сработает тайм-аут (около секунды) и опрос 10 железок займет время больше 2 сек, что выходит за рамки задачи. При распараллеливании запросов (много потоков) все запросы выполняются в течении 1 секунды, даже если устройства зависли.
3) можно конечно сделать отдельный поток при пересылке тэгов в WinCC, но пока я не вижу в этом особого смысла, так как множество потоков придется синхронизировать с еще одним.

Сегодня установил, что утечки памяти как раз идут при вызове функций Dll. сделал это следующим образом - заремировал все функции DLL и запустил программу, память ее не изменилась за несколько часов, а память программы с работающими функциями dll изменялась в большую сторону.

По поводу пересмотреть структуру приложения - пока у меня доводов мало (из тех, что мне привели). Я как раз пришел к той, что есть сейчас из за быстродействия данной структуры.

По поводу Suspend(); - это я не учел, сегодня подумаю. На вскидку, наверно нужно сначала запустить завершение потока, потом сделать ему Resume(); и следом все остальное.


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
Bima
Дата 11.4.2007, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 518
Регистрация: 15.8.2006

Репутация: 2
Всего: 2



Цитата

У тебя же во всех потоках вызывается куча методов разных объектов (причем вызов - в пределах объекта потока), начиная от сетевых компонентов и заканчивая главной формой. В таких условиях я вряд ли смогу указать тебе кусок кода, который вызывает утечки памяти, мне кажется сама структура программы ведёт к этому. Если честно, я вообще удивлен, как программа у тебя работает, да еще и стабильно (мне так не удалось её запустить ввиду отсутствия компонента Indy6.0 и некоего нестандартного спинедита), а уж мемори-лики в таких условиях - имхо дело обычное... Мне кажется, нужно попробовать пересмотреть структуру приложения и сделать один поток, обслуживающий подключенных клиентов, и один поток на обмен с WinCC, т.е. разделить задачу. При этом надо уделить серьезное внимание вопросу их синхронизации и синхронизации с главной формой. Ну и, конечно, имхо такие вещи лучше делать на WinAPI...

Очень конструктивная критика smile

1) в пределах объекта потока я НЕ вызываю компонеты из главной формы. Для передачи данных у меня существует блок TBlockList* Data, с критической секцией на доступ.
Для записи лог файла, я использую тоже критическую секцию, так что здесь затыков не должно быть.
2) если делать один поток и постоянно перенастраивать сетевые компонеты, то скорость сильно падает в зависимости от количества устройств. Допустим у меня есть 10 железяк с опросом в 1 секунду, если опрос нормальный, то он занимает до 100 мс, следовательно при нормальном опросе 10 устройств займет 1 сек, а если мне нужно опросить больше? Все это при нормальном опросе, а если хотя-бы пару железяк зависло, то при опросе сработает тайм-аут (около секунды) и опрос 10 железок займет время больше 2 сек, что выходит за рамки задачи. При распараллеливании запросов (много потоков) все запросы выполняются в течении 1 секунды, даже если устройства зависли.
3) можно конечно сделать отдельный поток при пересылке тэгов в WinCC, но пока я не вижу в этом особого смысла, так как множество потоков придется синхронизировать с еще одним.

Сегодня установил, что утечки памяти как раз идут при вызове функций Dll. сделал это следующим образом - заремировал все функции DLL и запустил программу, память ее не изменилась за несколько часов, а память программы с работающими функциями dll изменялась в большую сторону.

По поводу пересмотреть структуру приложения - пока у меня доводов мало (из тех, что мне привели). Я как раз пришел к той, что есть сейчас из за быстродействия данной структуры.

По поводу Suspend(); - это я не учел, сегодня подумаю. На вскидку, наверно нужно сначала запустить завершение потока, потом сделать ему Resume(); и следом все остальное.


--------------------
Чтобы дойти до цели, надо идти.

Клавиатура и мышь - это главные инструменты прогресса.
PM MAIL WWW   Вверх
pandrew
Дата 11.4.2007, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 213
Регистрация: 27.3.2006

Репутация: 3
Всего: 3



Цитата(Bima @  11.4.2007,  15:01 Найти цитируемый пост)
По поводу пересмотреть структуру приложения - пока у меня доводов мало (из тех, что мне привели). Я как раз пришел к той, что есть сейчас из за быстродействия данной структуры.

Самый простой довод "за": ты вынужден искать ошибку в куче кода (и нам пытался подсунуть). В правильной проге "критический" участок быстро локализуется. А быстродействием надо заниматься после верификации.

Цитата(Bima)
По поводу Suspend(); - это я не учел, сегодня подумаю. На вскидку, наверно нужно сначала запустить завершение потока, потом сделать ему Resume(); и следом все остальное. 
Я вообще не пользуюсь этими двумя чудными функциями. Зачем нужно приостанавливать боковой поток? Если он не нужен, пусть завершиться, если может пригодиться пусть крутится впустую.

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0842 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.