(erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
(erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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?
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.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [WinAPI] auf Zerstörung eines Prozesses warten
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 :(
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 :(
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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
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
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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.
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.
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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:
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:
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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.
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.
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
Nur mal rein prinzipiell: Wieso eigentlich stdout in eine Datei umleiten, wenn es nur temporär gebuffert werden soll?
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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 …)
(Nur in der Multithreaded-Version, wohlgemerkt …)
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
Ok, ich persönlich mach sowas dann einfach so, dass die Logdatei beim nächsten Start überschrieben wird... ;)
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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.
Trotzdem krass.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: (erledigt)[WinAPI] auf Zerstörung eines Prozesses warten
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?!
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:
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
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 2: Ich habe versucht, die Sache abzukürzen, indem ich DeleteFile() umgehe und das Löschen-Flag direkt setze. Mit DeleteFile() passiert folgendes:
- CreateFile(GENERIC_WRITE); // mein Code
- CloseHandle();
- CreateFile(DELETE, FILE_ATTRIBUTE_DELETE_ON_CLOSE) // DestroyFile() beginnt hier
- CloseHandle();
- … anderer Code, der dann ERROR_SHARING_VIOLATION erfährt
- CreateFile(GENERIC_WRITE | DELETE); // mein Code
- SetFileInformationByHandle(destroyOnClose);
- CloseHandle(); // hier sollte die Datei über den Jordan gehen
- … anderer Code
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