CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Aplikacja - brak odpowiedzi

Aplikacja - brak odpowiedzi

dział ogólny

Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 10:18

Napisałem kilka nakładek na programy "konsolowe", w sumie działają bo wykonują wszystkie założenia, a właściwie nie wszystkie, bo właśnie ...
po jakimś czasie przestają się odświeżać. Wygląda to, jakby aplikacja się zawiesiła, a system pokazuje na pasku programu "nie odpowiada". w rzeczywistości aplikacja czeka na zakończenie działania "childproccess", a po jego zakończeniu wyświetla komunikat o jego prawidłowym zakończeniu.
Aby wyświetlić komunikaty aplikacji konsolowej w moim programie, użyłem metody "pipe" ...
Czy jest coś, co powinienem zrobić, a czego nie zrobiłem ?? T.zn. wiem, że jest pewnie mnóstwo rzeczy bo jestem "programistą" niedzielnym, ale chodzi mi o ten konkretny "problem".
Pozdrawiam.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla

Re: Aplikacja - brak odpowiedzi

Nowy postprzez polymorphism » poniedziałek, 20 listopada 2017, 11:35

Ciężko odpowiedzieć na takie pytanie, bo nie wiadomo, co dokładnie robisz.

w rzeczywistości aplikacja czeka na zakończenie działania "childproccess"

Jak czeka? WaitForSingleObject?

użyłem metody "pipe"

CreatePipe + CreateProcess?
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2168
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    Windows 7Firefox

Re: Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 12:39

Wykonuje pętlę i czeka na jej zakończenie, a ta czeka na exit code dla procesu.
KOD cpp:     UKRYJ  
bool TMainForm::RunBatch(String _exe)     // utworzenie "Pipe", pisanie i czytanie
{
   int result;
   String mess;

   wchar_t buf[1024];           //i/o buffer


   STARTUPINFO si;
   SECURITY_ATTRIBUTES sa;
   SECURITY_DESCRIPTOR sd;               //security information dla pipes
   PROCESS_INFORMATION pi;
   HANDLE write_stdout,read_stdout;  //pipe handles

  if (IsWinNT())        //security descriptor dla WINDOWSA (Windows NT)
        {
           InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
           SetSecurityDescriptorDacl(&sd, true, NULL, false);
           sa.lpSecurityDescriptor = &sd;
        }
  else sa.lpSecurityDescriptor = NULL;
  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  sa.bInheritHandle = true;         //zezwalam na dziedziczenie handles

  if (!CreatePipe(&read_stdout,&write_stdout,&sa,0))  //pipe dla wyjścia
  {
    ErrorMessage("CreatePipe");
        return false;
  }

  GetStartupInfo(&si);      //startupinfo dla procesu

  si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
  si.wShowWindow = SW_HIDE;
  si.hStdOutput = write_stdout;
  si.hStdError = write_stdout;    


  if (!CreateProcess(NULL, _exe.c_str(),NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
        {
           ErrorMessage("CreateProcess");
           CloseHandle(write_stdout);
           CloseHandle(read_stdout);
           return false;
        }
  unsigned long exit=0;  //kod wyjścia
  unsigned long bRead;   //bytes przeczytane
  unsigned long aVail;   //bytes do przeczytania
  int pos;
  bzero(buf);
  Ekran->SetFocus(); //Memo

  for(;;)      //główna pętla
  {
    GetExitCodeProcess(pi.hProcess,&exit);      //czekam na zakończenie procesu
    if (exit != STILL_ACTIVE)
      break;
        PeekNamedPipe(read_stdout,buf,1023,&bRead,&aVail,NULL);
        //check to see if there is any data to read from stdout
        if (bRead != 0)
    {
      bzero(buf);
          if (aVail > 1023)
      {
                while (bRead >= 1023)
                {
                  ReadFile(read_stdout,buf,1023,&bRead,NULL);  //"wyłapuję" dane wyjściowe pipe
                  mess = String((wchar_t*)buf);
                  pos = mess.Pos("\n");
                  while(pos > 0)
                   {
                         Ekran->Lines->Add(mess.SubString(1, pos-1));  //"przechwycone" dane do Memo
                         mess = mess.Delete(1, pos);
                         pos = mess.Pos("\n");
                   }
                  if(!mess.IsEmpty())
                   {
                          Ekran->Lines->Add(mess);
                   }

          bzero(buf);  // czyszczenie bufora
        }
      }
          else
                {
                  ReadFile(read_stdout,buf,1023,&bRead,NULL);
                  mess = String((char*)buf);
                  pos = mess.Pos("\n");
                  while(pos > 0)
                   {
                         Ekran->Lines->Add(mess.SubString(1, pos-1));
                         mess = mess.Delete(1, pos);
                         pos = mess.Pos("\n");
                   }
                  if(!mess.IsEmpty())
                   {
                         Ekran->Lines->Add(mess);
                   }
                }
        }
  }
  CloseHandle(pi.hThread);
  CloseHandle(pi.hProcess);
  CloseHandle(write_stdout);
  CloseHandle(read_stdout);
  return true;

}
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla

Re: Aplikacja - brak odpowiedzi

Nowy postprzez polymorphism » poniedziałek, 20 listopada 2017, 14:06

Kilka uwag:
KOD cpp:     UKRYJ  
unsigned long exit = 0; //kod wyjścia
    unsigned long bRead; //bytes przeczytane
    unsigned long aVail; //bytes do przeczytania

Nie unsigned long, tylko DWORD. Powinieneś używać typów takich, jakie są w dokumentacji.

KOD cpp:     UKRYJ  
for (;;) //główna pętla

Dlaczego nie while?
KOD cpp:     UKRYJ  
       GetExitCodeProcess(pi.hProcess, &exit); //czekam na zakończenie procesu
        if (exit != STILL_ACTIVE) break;

        PeekNamedPipe(read_stdout, buf, 1023, &bRead, &aVail, NULL);

Jeśli dobrze pamiętam, proces może się skończyć, ale w buforze potoku mogą być jeszcze jakieś dane do odczytania. Tak bym zrobił:
KOD cpp:     UKRYJ  
    while(PeekNamedPipe(read_stdout, NULL, 0, NULL, &aVail, NULL))
    {
        if(aVail == 0 && WaitForSingleObject(pi.hProcess, 1) != WAIT_TIMEOUT) break;

        ...

        Application->ProcessMessages(); // to odblokuje GUI
    }


KOD cpp:     UKRYJ  
    if (aVail > 1023)
    {
        ...
        mess = String((wchar_t*)buf);
    }
    else
    {
        ...
        mess = String((char*)buf);
    }
 

Dlaczego raz wchar_t*, raz char*? Co ma ilość odczytanych bajtów do sposobu kodowania znaków? I skąd ta pewność, że dane czytane to znaki szerokie? Bloki if i else zawierają prawie taki sam kod. Po co?


Na razie tyle...
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2168
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    Windows 7Firefox

Re: Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 14:17

quote="polymorphism"]Nie unsigned long, tylko DWORD. Powinieneś używać typów takich, jakie są w dokumentacji.[/quote]
fakt .. dziękuję.
polymorphism napisał(a):Dlaczego nie while?

bo mi nie działało, i za cienki jestem, żeby wiedzieć dlaczego.
polymorphism napisał(a):Jeśli dobrze pamiętam, proces może się skończyć, ale w buforze potoku mogą być jeszcze jakieś dane do odczytania.
[
jak na razie wczytuje wszystkie dane.

"Application->ProcessMessages(); // to odblokuje GUI" - że też o tym nie pomyślałem .. 8-)
polymorphism napisał(a):Dlaczego raz wchar_t*, raz char*? Co ma ilość odczytanych bajtów do sposobu kodowania znaków? I skąd ta pewność, że dane czytane to znaki szerokie? Bloki if i else zawierają prawie taki sam kod. Po co?

To były poprawki, bo miałem kłopoty ze znakami, w jednym miejscu zmieniłem, w innym nie ... ogólnie błąd leżał gdzie indziej ale już nie poprawiałem.

Ogromne dzięki za sugestie i porady ... zaraz wypróbuję.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla

Re: Aplikacja - brak odpowiedzi

Nowy postprzez polymorphism » poniedziałek, 20 listopada 2017, 14:21

Jeszcze jedna uwaga:
KOD cpp:     UKRYJ  
  si.hStdOutput = write_stdout;
  si.hStdError = write_stdout;  

Nie jestem pewny, czy to jest dobrze. Wydaje mi się, że do hStdError powinieneś przypisać oddzielny uchwyt (zduplikuj write_stdout funkcją DuplicateHandle()).
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2168
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    Windows 7Firefox

Re: Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 14:55

polymorphism napisał(a):
KOD cpp:     UKRYJ  
    while(PeekNamedPipe(read_stdout, NULL, 0, NULL, &aVail, NULL))
    {
        if(aVail == 0 && WaitForSingleObject(pi.hProcess, 1) != WAIT_TIMEOUT) break;

        ...

        Application->ProcessMessages(); // to odblokuje GUI
    }
 

Tak jak w kilku innych przypadkach while, których próbowałem, nie wychodzi z pętli.


[quote="polymorphism"]Nie jestem pewny, czy to jest dobrze. Wydaje mi się, że do hStdError powinieneś przypisać oddzielny uchwyt (zduplikuj write_stdout funkcją DuplicateHandle()).
Korzystałem z dokumentacji i przykładów Microsoftu.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla

Re: Aplikacja - brak odpowiedzi

Nowy postprzez polymorphism » poniedziałek, 20 listopada 2017, 15:45

Sprawdź debuggerem, co zwraca PeekNamedPipe(). Jeśli nie wychodzi z pętli, to znaczy, że funkcja zwraca TRUE, aVail jest niezerowa i proces potomny cały czas działa.

Być może nie czytasz wszystkiego z potoku i Ci się "zawiesza". Tak zrób:
KOD cpp:     UKRYJ  
    while(PeekNamedPipe(read_stdout, NULL, 0, NULL, &aVail, NULL))
    {
        if(aVail == 0 && WaitForSingleObject(pi.hProcess, 1) != WAIT_TIMEOUT) break;

        if(ReadFile(read_stdout, buf, std::min(aVail, 1023), &bRead, NULL) == FALSE) break;

        /* tu przetwarzasz to, co jest w 'buf' */

        Application->ProcessMessages();
    }
 
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2168
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    Windows 7Firefox

Re: Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 16:59

Tu już mnie niestety przeceniasz ...
Program child wykonuje całą pracę
Funkcja RunBatch ... wykonuje wszystko , aż do wyczyszczenia bufora, zakańcza trzy procesy

Module Unload: WPDSHEXT.dll. Process MkvBatch.exe (25168)
Thread Exit: Thread ID: 3484. Process MkvBatch.exe (25168)
Thread Exit: Thread ID: 24764. Process MkvBatch.exe (25168)
Thread Exit: Thread ID: 7156. Process MkvBatch.exe (25168)
Thread Exit: Thread ID: 17068. Process MkvBatch.exe (25168)
Thread Start: Thread ID: 3024. Process MkvBatch.exe (25168)

i .... wisi.

Kiedy pierwszy raz próbowałem użyć "pipe", to zawsze miałem ten sam problem, aż do momentu kiedy załapałem, że nie zamykałem procesu.

Użyłem twojego przykładu i ...

"[bcc32 Error] Unit1.cpp(256): E2285 Could not find a match for 'std::min<_Ty>(unsigned long,int)' "
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla

Re: Aplikacja - brak odpowiedzi

Nowy postprzez polymorphism » poniedziałek, 20 listopada 2017, 18:39

Daj tak: std::min<DWORD>(aVail, 1023)
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2168
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 7 Pro
Windows 8.1
Linux Mint 19
Kompilator: Visual Studio 2015 Community
CodeLite (MinGW)
MSYS2 (MinGW, clang)
g++
Gadu Gadu: 0
    Windows 7Firefox

Re: Aplikacja - brak odpowiedzi

Nowy postprzez pioro700 » poniedziałek, 20 listopada 2017, 18:55

polymorphism napisał(a):Daj tak: std::min<DWORD>(aVail, 1023)

To nic nie daje i nie wiem czemu. Użyłem standardowej funkcji Buildera "Min", która robi dokładnie to samo, czyli zwraca mniejszą wartość. W niczym to nie zmienia działania.

Tak naprawdę to, to od czego zacząłem ten wątek, zostało rozwiązane jednym "Application->ProcessMessages();"

Ale korzystając z porad mądrzejszych, postanowiłem się czegoś nauczyć i zacząłem dalej grzebać przy kodzie ...

Całe założenie mojej aplikacji/nakładki, to multipleksowanie plików wideo i subtitles. Robi to aplikacja "mkvmerge.exe" i jest na nią doskonałe GUI, czyli MKVToolNix.
Problemem dla mnie było, że w przypadku seriali, czyli np. 25 odcinków, musiałem 25 razy ładować pliki, zmieniać ustawienia .... i multipleksować.
Nie będę się rozpisywał dlaczego tak robię, ale miałem potrzebę napisania innej nakładki.

Po kilku próbach według twoich rad, zoptymalizowałem kod do dwóch wersji (nie będę wklejał całego kodu, tylko tę nową część):
KOD cpp:     UKRYJ  
while(PeekNamedPipe(read_stdout,buf,1023,&bRead,&aVail,NULL))
        {
                GetExitCodeProcess(pi.hProcess,&exit);
                if(exit != STILL_ACTIVE)
                   break;
                ReadFile(read_stdout,buf,1023,&bRead,NULL);  //read the stdout pipe
                mess = String((char*)buf);
                pos = mess.Pos("\n");
                while(pos > 0)
                  {
                         Ekran->Lines->Add(mess.SubString(1, pos-1));
                         mess = mess.Delete(1, pos);
                         pos = mess.Pos("\n");
                  }
                if(!mess.IsEmpty())
                  {
                         Ekran->Lines->Add(mess);
                  }

                  bzero(buf);

                Application->ProcessMessages();
        }

Ta część gra i buczy, pokazuje cały przebieg operacji, procent wykonania i wszystko co tylko mkvmerge.exe wysyła. Ale ....
jest też druga wersja, która pokazuje tylko i wyłącznie informację o aplikacji "mkvmerge v18.0.0 ('Apricity') 64-bit", również tworzy nowe zmultiplikowane pliki ....
tylko jakieś 40 razy szybciej :o

KOD cpp:     UKRYJ  
do
        {
                PeekNamedPipe(read_stdout,buf,1023,&bRead,&aVail,NULL)
               
                GetExitCodeProcess(pi.hProcess,&exit);
               
                ReadFile(read_stdout,buf,1023,&bRead,NULL);  
                mess = String((char*)buf);
                pos = mess.Pos("\n");
                while(pos > 0)
                  {
                         Ekran->Lines->Add(mess.SubString(1, pos-1));
                         mess = mess.Delete(1, pos);
                         pos = mess.Pos("\n");
                  }
                if(!mess.IsEmpty())
                  {
                         Ekran->Lines->Add(mess);
                  }

                  bzero(buf);

                Application->ProcessMessages();
        } while(exit != STILL_ACTIVE)

  CloseHandle(pi.hThread);
  CloseHandle(pi.hProcess);
  CloseHandle(write_stdout);
  CloseHandle(read_stdout);


Rezultat pierwszej wersji :

mkvmerge v18.0.0 ('Apricity') 64-bit
'Q:\Video\Hawaii Five-0 Season 6\hawaii.five-0.2010.601.hdtv-lol.mp4': Using the demultiplexer for the format 'QuickTime/MP4'.
'Q:\Video\Hawaii Five-0 Season 6\hawaii.five-0.2010.601.hdtv-lol.srt': Using the demultiplexer for the format 'SRT subtitles'.
Q:\Video\Hawaii Five-0 Season 6\hawaii.five-0.2010.601.hdtv-lol.mp4' track 0: Using the output module for the format 'AVC/h.264'.
'Q:\Video\Hawaii Five-0 Season 6\hawaii.five-0.2010.601.hdtv-lol.mp4' track 1: Using the output module for the format 'AAC'.
'Q:\Video\Hawaii Five-0 Season 6\hawaii.five-0.2010.601.hdtv-lol.srt' track 0: Using the output module for the format 'text subtitles'.
The file 'Q:\Video\Hawaii Five-0 Season 6\Hawaii 5-0 S06E01.mkv' has been opened for writing.
Progress: 0%
Progress: 4%
...
Progress: 100%

The cue entries (the index) are being written...
Multiplexing took 16 seconds.


mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 15 seconds.


mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 18 seconds.


mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 23 seconds.

mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 23 seconds.


mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 19 seconds.


mkvmerge v18.0.0 ('Apricity') 64-bit
...
...
Multiplexing took 25 seconds.

Proces zakończony powodzeniem !

jak łatwo podliczyć, dla 7 plików - 139 sekund

Druga wersja:

mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit
mkvmerge v18.0.0 ('Apricity') 64-bit

Proces zakończony powodzeniem !
Czas to około 8 sekund.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 27
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 4
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsMozilla


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 1 gość

cron