(erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

(erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Prozess erzeugen ist einfach (CreateProcess()).

Prozess freigeben auch (CloseHandle()).

Schwieriger ist es aber, auf die tatsächliche Zerstörung zu warten. CloseHandle() gibt den Prozess frei; die Zerstörung erfolgt irgendwann später, wenn alle Handles geschlossen sind. Ich möchte gern auf den Zeitpunkt warten, an dem diese Zerstörung abgeschlossen ist. Aber wie?
Zuletzt geändert von Krishty am 06.01.2016, 20:40, insgesamt 1-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Nein, das wartet nur, bis der letzte Thread im Prozess fertig ist. Danach existiert der Prozess weiter (schließlich besitzt du noch ein Handle darauf, mit dem du z.B. den Rückgabewert abfragen könntest) und wird erst irgendwann zerstört, nachdem alle Handles geschlossen sind.

In meinem Fall hält der Prozess noch seine stdio-Handles offen bis er komplett weg ist, und ich kann deswegen meine temporären Dateien nicht löschen :(
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Nicht die Prozesszerstörung ist das Problem, sondern das Freigeben der Dateien. DeleteFile() schlägt auf zwei Drittel meiner Daten fehl, wenn ich nicht vorher Sleep(300) einbaue. Und auch andere Prozesse, die ich abfertige, erfordern vorher ein kurzes Schlafen weil sie sonst keinen Zugriff auf ihre just geschriebenen Input-Dateien kriegen. Ich muss quasi hinter jedes CloseHandle() und vor jeden Fremdprozessaufruf Sleep(300) einbauen.

OMFG, das darf doch nicht wahr sein, oder?!

Und es geht erst los, wenn ich Multi-Threading benutze. So lange ich nur in einem Thread bleibe, ist alles perfekt. Sobald ein zweiter dazukommt (nicht einmal zum Schließen von Dateien fremder Threads, sondern einfach einer der ebenfalls Dateien öffnet und schließt) laufen in der ganzen Anwendung die Dateipuffer amok. WTF
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Totaler Irrsinn. DeleteFile() klappt tadellos so lange nur ein Thread Dateien anlegt und löscht. Aber sobald Multithreading ins Spiel kommt, geht das total vor die Hunde und schlägt dauernd fehl mit "Die Funktion kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird", obwohl ich bereits alle Handles auf die Datei geschlossen habe.

Die einzige Lösung, die ich bis jetzt habe, ist, DeleteFile() in einer Schleife aufzurufen und zwischendurch jedes Mal 100 ms zu warten. Irgendwann (nach 0 bis 700 ms auf diesem System hier; YMMV) ist die Datei dann verfügbar und wird gelöscht.

Man liest Threads wie diesen, bei denen man denkt, Sind die noch bei Trost, in einem Spinlock auf eine Datei zu warten?!, und dann … muss man’s selber genauso machen. WTF.

  bool deleteFileReally(UTF16Unit const * path) {
    start:
    if(0 != DeleteFileW(path)) {
      return yes;
    } else if(ERROR_SHARING_VIOLATION == GetLastError()) {
      Sleep(100); // some suggest progressive waiting here
      goto start;
    } else {
      return no; // Error!
    }
  }


Hier macht CreateFile() mit FILE_FLAG_DELETE_ON_CLOSE() keinen Unterschied gegenüber DeleteFile(), also habe ich das Kürzere genommen.

Nachtrag: SQLite macht es genauso.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von NytroX »

Ein Problem könnte auch sein, dass man unter Windows grundsätzlich keine Dateien löschen kann.
Stattdessen markiert man sie als "Hallo Windows, bitte bei Gelegenheit mal löschen"
Klingt erstmal komisch, vor allem weil die Funktion "PlsMarkForDeletionKThx()" anstatt "DeleteFile()" heißen sollte.

z.B. Verzeichnisse rekursiv löschen, indem man sie in einem Loop durchgeht und die Dateien löscht, das funktioniert grundsätzlich nicht richtig (naja, klappt in 90% der Fälle, vermutlich damit man das nicht gleich bemerkt).
Stattdessen sollte man die Datei aus der zu löschenden Hierarchie heraus-moven und dann deleten.

Hast du mal versucht, die Datei vorher einfach zu moven, und dann zu löschen?
Habs jetzt nicht selbst probiert, aber angeblich macht man neuerdings unter Windows so... vielleicht löst das auch das Access-Problem. Oder das moven geht halt einfach auch nicht :roll:
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Naja; die Dokumentation garantiert schon, dass die Datei mit Schließen des letzten Handles gelöscht wird. Nur kehrt CloseHandle() halt zurück, bevor der Kernel seins geschlossen hat.

Habe gerade keine Zeit zu testen, aber Verschieben schlägt bei mir auch an einigen Stellen fehl. Sogar Anlegen einer neuen Daten kracht, wenn da noch eine Alte rumliegt, die Milisekunden vorher gelöscht und geschlossen wurde. Ein Trauerspiel. Löschen funktioniert hingegen mit der Schleife.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von dot »

Nur mal rein prinzipiell: Wieso eigentlich stdout in eine Datei umleiten, wenn es nur temporär gebuffert werden soll?
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Ich will nach einem Absturz eine Logdatei haben (gelöscht wird nur, wenn’s reibungsfrei lief), und an Pipes habe ich mich einfach noch nicht rangetraut weil die Ausgabe keinen uniformen Standards zu folgen scheint: Manche Tools erwarten in stdin die Eingabedatei, schreiben die Ergebnisdatei nach stdout, alle Meldungen nach stderr, und seeken dann noch darin rum. Ich habe es heute nacht erst geschafft, dass die meisten Aufrufe nicht wegen Invalid Handles zusammenbrechen.

(Nur in der Multithreaded-Version, wohlgemerkt …)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von dot »

Ok, ich persönlich mach sowas dann einfach so, dass die Logdatei beim nächsten Start überschrieben wird... ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Ich führe aber tausende unzusammenhängende Jobs aus (davon ein Dutzend parallel), und die sollen nicht *alle* in der Logdatei landen (zumal die UI die Statusanzeigen getrennt halten muss). Darum kriegt ein Job ein Log, und
  • wenn alles reibungslos lief, wird es wieder gelöscht
  • bei Fehlern wird der Inhalt fest gespeichert und das ursprüngliche Log gelöscht
  • falls alles mit Pauken und Trompeten abrauscht, bleibt eine Log-Datei auf der Platte zurück.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Zum Teil scheint die Verzögerung nach dem Schließen von Dateien auch von mir provoziert zu sein, weil die Threads alle mit niedrigerer Priorität (_BELOW_NORMAL) laufen. Da kann es schonmal bis zu zehn Sekunden(!) dauern, bis Windows auf mein CloseHandle() reagiert.

Trotzdem krass.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten

Beitrag von Krishty »

Jetzt bin ich so weit: http://superuser.com/questions/510800/h ... -windows-7

Scheinbar rufe zwar ich CloseHandle() auf, aber der Kind-Prozess, dem die Datei als stdout zugewiesen war und den ich schon viele Milisekunden zuvor beendet habe, schließt die Datei dann tatsächlich. Also: Mein Prozess öffnet die Datei, aber der andere schließt sie wieder, jedoch ohne CloseHandle() aufzurufen und während er schon längst zerstört ist. Wtf?!

Code: Alles auswählen

0	fltmgr.sys	FltAcquirePushLockShared + 0x907	0xfffff880011ad067	C:\Windows\system32\drivers\fltmgr.sys
1	fltmgr.sys	FltIsCallbackDataDirty + 0xa39	0xfffff880011ae329	C:\Windows\system32\drivers\fltmgr.sys
2	fltmgr.sys	fltmgr.sys + 0x16c7	0xfffff880011ac6c7	C:\Windows\system32\drivers\fltmgr.sys
3	ntoskrnl.exe	MmCreateSection + 0xbcff	0xfffff80002f9805f	C:\Windows\system32\ntoskrnl.exe
4	ntoskrnl.exe	NtWaitForSingleObject + 0xf4e	0xfffff80002f8654e	C:\Windows\system32\ntoskrnl.exe
5	ntoskrnl.exe	NtWaitForSingleObject + 0xbbf	0xfffff80002f861bf	C:\Windows\system32\ntoskrnl.exe
6	ntoskrnl.exe	RtlNtStatusToDosError + 0x13e4	0xfffff80002f47380	C:\Windows\system32\ntoskrnl.exe
7	ntoskrnl.exe	RtlNtStatusToDosError + 0x12dc	0xfffff80002f47278	C:\Windows\system32\ntoskrnl.exe
8	ntoskrnl.exe	RtlNtStatusToDosError + 0x196e	0xfffff80002f4790a	C:\Windows\system32\ntoskrnl.exe
9	ntoskrnl.exe	RtlCopySidAndAttributesArray + 0x17f2	0xfffff80002f64572	C:\Windows\system32\ntoskrnl.exe
10	ntoskrnl.exe	RtlNtStatusToDosError + 0x152c	0xfffff80002f474c8	C:\Windows\system32\ntoskrnl.exe
11	ntoskrnl.exe	KeSynchronizeExecution + 0x3a23	0xfffff80002c8e853	C:\Windows\system32\ntoskrnl.exe
Nachtrag: Noch mehr Leute mit diesem Problem, und mit nichts als Workarounds.


Nachtrag 2: Ich habe versucht, die Sache abzukürzen, indem ich DeleteFile() umgehe und das Löschen-Flag direkt setze. Mit DeleteFile() passiert folgendes:
  1. CreateFile(GENERIC_WRITE); // mein Code
  2. CloseHandle();
  3. CreateFile(DELETE, FILE_ATTRIBUTE_DELETE_ON_CLOSE) // DestroyFile() beginnt hier
  4. CloseHandle();
  5. … anderer Code, der dann ERROR_SHARING_VIOLATION erfährt
Nun habe ich SetFileInformationByHandle() benutzt, um abzukürzen:
  1. CreateFile(GENERIC_WRITE | DELETE); // mein Code
  2. SetFileInformationByHandle(destroyOnClose);
  3. CloseHandle(); // hier sollte die Datei über den Jordan gehen
  4. … anderer Code
Vorher stolperte der "andere" Code über ERROR_SHARING_VIOLATION. Jetzt ist es ERROR_ACCESS_DENIED. Scheinbar ist die Datei beim Öffnen noch vorhanden, aber danach direkt nicht mehr verfügbar. WTF!

Was mich an der Sache am meisten wurmt ist, dass der "andere" Code mit dem Fehler leben muss. Den habe ich nicht geschrieben und den kann ich nicht darauf vorbereiten. Ich kann nichts tun, um ihm ein konsistentes Dateisystem zu hinterlassen (außer, nach jeder Operation zehn Sekunden zu schlafen). wtfwtfwtf
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten