"race condition" bei Verwendung von system() ?

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

"race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 16:25:45

Ich habe da vor einiger Zeit ein Programm geschrieben, dass mir die Parameter für imagemagick ausrechnet und dieses dann auch startet. Anschließend soll dann mit display das Ergebnis angezeigt werden.
Dabei bekomme ich immer wieder mal folgende Fehlermeldung:

Code: Alles auswählen

display-im6.q16: unable to open image `Traktor1.jpg': Datei oder Verzeichnis nicht gefunden @ rror/blob.c/OpenBlob/2701.
display-im6.q16: no decode delegate for this image format `' @ error/constitute.c/ReadImage/504.
Der verursachende Codeabschnitt ist:

Code: Alles auswählen

    ...
    sprintf( buf, "-quality %d %s", image_quality, img->name );
    strcat( workbuf, buf );
    if ( debug_flag > 1 )
    	printf( "\ndebug: %s\n\n", workbuf ); // Ausgabe der Kommandozeile
    system( workbuf );
    sprintf( workbuf, "display %s &", img->name );
    system( workbuf );  // show the picture
    ...
Das erzeugte Bild ist aber da und wird auch sofort im Dateimanager angezeigt. Ich dachte bisher immer, das system() erst zurückkehrt, wenn der Auftrag erledigt ist.

Eine typische Kommandozeile sieht so aus (editiert):

Code: Alles auswählen

debug: convert -size 480x170! xc:#FFFFFF 
-draw "image over 10,10 100,150 'IMGP1117.JPG'" \
-draw "image over 120,47 170,113 'IMGP1116.JPG'" \
-draw "image over 300,47 170,113 'IMGP1118.JPG'" \
-fill "#4040FF" -font Helvetica-Bold -pointsize 28 \
-gravity center -annotate 0x0+55-61 "Eicher Traktor" -quality 95 Traktor1.jpg
So einen Bandwurm möchte man ja nicht von Hand eingeben.

Das Problem existiert übrigens schon seit 2008 auf mehreren PCs, aber jetzt reicht es mir.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 17:56:55

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 16:25:45
Ich dachte bisher immer, das system() erst zurückkehrt, wenn der Auftrag erledigt ist.
Das ist auch so, siehe:
Manpage system(3) hat geschrieben: DESCRIPTION
system() executes a command specified in command by call‐
ing /bin/sh -c command, and returns after the command has
been completed.
Keine Ahnung woher dein Problem kommt.


Btw: Das strcat() solltest du loswerden. Du verwendest eh schon sprintf(), das kannst du doch darum erweitern, dann aber besser auch mit snprintf() oder halt lieber strncat().
Use ed once in a while!

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 18:45:57

Keine Ahnung woher dein Problem kommt.
Früher trat das Problem etwa einmal pro Woche auf. Jetzt, wo ich dabei bin, da neue Features einzubauen, tritt da Problem etwa jedes 10-te bis 20-ste Mal auf. Hatte schon das Dateisystem im Verdacht aber dann müssten sich reiserfs, ext3 und ext4 sehr ähnlich sein.

Aber ich habe nochmal weiter gegrübelt. Könnte das Problem durch den Aufruf von display (das "&" Zeichen) verursacht werden. Danach wird die Datei ja noch einmal geöffnet, um einen Kommentar einzutragen. Die Datei wird zwar erstmal nur lesend geöffnet, aber wenn der Programmteil zu schnell ist ...

Code: Alles auswählen

    ...
    sprintf( workbuf, "display %s &", img->name );
    system( workbuf );  // show the picture
    if ( strlen( rembuf ) ){ // Kommentar einfuegen lassen
        switch( ftype ) {
            case 1: // JPG
                res = jpg_put_com( img->name, rembuf );
                break;
            case 2: // PNG
                res = png_put_com( img->name, rembuf, "Comment" );
                break;
            case 3: // GIF
                res = gif_put_com( img->name, rembuf );
                break;
            default:
                res = 0;
                fprintf( stderr, "Fehler: unbekannter Dateityp!\n" );
                break;
        }
        if( res == 0 ) {
            fprintf( stderr, "Fehler: Kommentar einfügen nicht möglich!\n" );
        }
    }
    ...
Btw: Das strcat() solltest du loswerden. ...
Ja, ich wollte das schon immer mal komplett dynamisch machen, ähnlich wie std::string. In einem anderen Programm habe ich das auch schon. Bisher waren 4KB Puffer aber immer ausreichend.

Eigentlich wollte ich hier noch das Ergebnisbild zeigen, aber das scheint hier nicht so einfach möglich zu sein (keine passende URL).

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 25.05.2021 19:50:23

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 18:45:57
Könnte das Problem durch den Aufruf von display (das "&" Zeichen) verursacht werden. Danach wird die Datei ja noch einmal geöffnet, um einen Kommentar einzutragen.
Ja, so ohne weiter Einschränkungen und Hintergründe ist das erstmal eine blöde Idee. display versucht die Datei zu öffnen, die je nach Timing gerade wieder überschrieben wird. Je nach Auslastung des Systems, Mondphase und anderem tritt daher, wie du beobachtet hast, mal ein Problem auf, mal nicht. Dass die Datei gerade wieder überschrieben wird, passt durchaus ganz gut zu den beobachteten Fehlermeldungen.

Reicht es nicht, die Datei einfach – dann vllt ohne & – nach dem Kommentarschreiben anzuzeigen? Oder dauert letzteres unerwünscht lange?

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 18:45:57
Eigentlich wollte ich hier noch das Ergebnisbild zeigen, aber das scheint hier nicht so einfach möglich zu sein (keine passende URL).
Du meinst hier im Forum? Du kannst das Bild in der Galerie hochladen und dann in einem Beitrag mit dem [album]-Tag einbinden.
Manchmal bekannt als Just (another) Terminal Hacker.

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 20:23:38

Ja, ich habe jetzt die Anzeige des Bildes ans Ende gesetzt. Nach über 60 Versuchen keine Fehlermeldung mehr. Zu meiner Entschuldigung kann ich nur das alter der Ausgangsversion anführen und die Tatsache das es ursprünglich nur ein Bash Script war.

Das mit dem "&" am Ende ist aber wichtig. Ich muss das Ergebnis sehen, um ggf. die Bilderzeugung mit geänderten Parametern (Schriftgröße, Bildbox) zu wiederholen.

3184
Wie man hier sieht, ist die Textmenge normalerweise nicht groß, ca. 500 Bytes plus die Überschrift als Kommentar. Wenn man genau hinsieht, erkennt man auch dass hier die Bildbox beim zweiten Versuch von 150x150 auf 170x150 erweitert wurde. Deswegen das "&".

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 20:28:28

Ich sehe kein Problem mit dem `&' oder einem Ueberschreiben.

Das Script macht im Kern doch folgendes:

Code: Alles auswählen

convert ... foo.jpg
display foo.jpg &
D.h. `convert' laeuft synchron. D.h. `display' wird erst aufgerufen wenn `convert' fertig ist.

Dass `display' asynchron laeuft ist doch irrelevant.

Wie kommst du darauf, dass die Datei ueberschrieben wird? Ich sehe keine Schleife oder Hinweise, dass das Script auf immer der gleichen Datei arbeitet.


Man koennte natuerlich mal mit einem `sleep 1' zwischen den zwei Befehlen arbeiten oder zum Debuggen ein `stat foo.jpg' dazwischen (plus davor und danach) einbauen ... bzw. jeweils die C-Aequivalente.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 20:33:21

Aeh, Moment ... gibt es ein oder zwei `display'/`convert' in dem Script? Welcher Befehl genau erzeugt die Fehlermeldung? Ist es der den du gepostet hast oder evtl. ein zweiter, den du nicht gepostet hast?

Wenn wir das ganze Script sehen koennten waere das natuerlich hilfreicher ... oder zumindest den Ablauf des kompletten Scriptes verstehen wuerden.
Use ed once in a while!

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 25.05.2021 20:38:32

Meillo hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 20:28:28
Wie kommst du darauf, dass die Datei ueberschrieben wird? Ich sehe keine Schleife oder Hinweise, dass das Script auf immer der gleichen Datei arbeitet.
Das habe ich mal so in dakuans Ergänzung reingedeutet – ohne die genaue Funktionsweise der Funktionen zu kennen:
dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 18:45:57

Code: Alles auswählen

    ...
    sprintf( workbuf, "display %s &", img->name );
    system( workbuf );  // show the picture
    if ( strlen( rembuf ) ){ // Kommentar einfuegen lassen
        switch( ftype ) {
            case 1: // JPG
                res = jpg_put_com( img->name, rembuf );
                break;
            case 2: // PNG
                res = png_put_com( img->name, rembuf, "Comment" );
                break;
            case 3: // GIF
                res = gif_put_com( img->name, rembuf );
                break;
            default:
                res = 0;
                fprintf( stderr, "Fehler: unbekannter Dateityp!\n" );
                break;
        }
        if( res == 0 ) {
            fprintf( stderr, "Fehler: Kommentar einfügen nicht möglich!\n" );
        }
    }
    ...
Das verwendet ja, wie der display-Aufruf, den img->name. Ich nehme mal stark an, dass hinter den *_put_com etwas schreibendes steckt. Damit wäre es so ein Ablauf:

Code: Alles auswählen

convert ... foo.jpg
display foo.jpg &
x_put_com foo.jpg
Den stelle ich mir fehleranfällig vor.
Manchmal bekannt als Just (another) Terminal Hacker.

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 20:49:33

Wie kommst du darauf, dass die Datei ueberschrieben wird? Ich sehe keine Schleife oder Hinweise, dass das Script auf immer der gleichen Datei arbeitet.
Ich halte das jetzt schon für möglich. Was die Kommentareinfügefunktionen machen ist folgendes.

Die Originaldatei wird gelesen und gleichzeitig eine temporäre Datei erzeugt. Wenn das erfolgreich war, wird die Originaldatei gelöscht und die andere umbenannt.

Ich hatte mir kürzlich das Buch "The Linux Programming Interface" besorgt. Da werden in den Beispielen oft Probleme erwähnt, die dadurch entstehen, dass nicht alle Operationen "atomar" sind. Danach könnte ich mir vorstellen, das display genau in die Lücke zwischen remove und rename greift.

Anders kann ich mir das jetzt nicht erklären. Das Problem ist möglicherweise erst dadurch nervig geworden, dass ich jetzt von einer single-core CPU auf 8 Kerne umgestiegen bin. Da ist das Timing wohl etwas kritischer. Muss ich wohl zukünftig besser im Auge behalten.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 20:50:07

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 18:45:57
Btw: Das strcat() solltest du loswerden. ...
Ja, ich wollte das schon immer mal komplett dynamisch machen, ähnlich wie std::string. In einem anderen Programm habe ich das auch schon. Bisher waren 4KB Puffer aber immer ausreichend.
Komplett dynamisch macht es technisch aufwaendiger, aber du kannst alles lassen wie es ist, wenn du nur statt sprintf() eben snprintf() und statt strcat() strncat() verwendest, dann pruefst du die Laenge. Es funktioniert dann zwar nicht fuer >4k lange Strings, aber es geht dann wenigstens nicht kaputt, sondern kappt den String an der Stelle.


@JTH: Da magst du Recht haben. Wir werden es nur erfahren, wenn dakuan uns die noetigen Einblicke bietet (oder feltel endlich mal die Glaskugeln fuer uns Mods bestellt :-P ).
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 21:00:05

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 20:49:33
Wie kommst du darauf, dass die Datei ueberschrieben wird? Ich sehe keine Schleife oder Hinweise, dass das Script auf immer der gleichen Datei arbeitet.
Ich halte das jetzt schon für möglich. Was die Kommentareinfügefunktionen machen ist folgendes.

Die Originaldatei wird gelesen und gleichzeitig eine temporäre Datei erzeugt. Wenn das erfolgreich war, wird die Originaldatei gelöscht und die andere umbenannt.
Ist die Kommentarfunktion immer im Spiel oder ist die optional? Tritt das Problem nur auf wenn die Kommentarfunktion genutzt wird oder auch sonst?

Aber was du beschreibst sollte dennoch funktionieren, AFAICS.
Ich hatte mir kürzlich das Buch "The Linux Programming Interface" besorgt. Da werden in den Beispielen oft Probleme erwähnt, die dadurch entstehen, dass nicht alle Operationen "atomar" sind. Danach könnte ich mir vorstellen, das display genau in die Lücke zwischen remove und rename greift.
Das `display' wird doch schon viel frueher aufgerufen ... Wird dann ohne User-Interaktion direkt der Kommentar eingefuegt? Dann koennte es schon sein, dass das Starten von `display' im Hintergrund laenger dauert als das Kopieren und Umbenennen der Bilddatei. Sobald du aber eine User-Interaktion dazwischen hast, sollte das kein Problem mehr sein. Zudem sollten mehr und schnellere Kerne das Starten von `display' beschleunigen und damit das Problem reduzieren.


Ehrlich gesagt stochere ich immer noch ziemlich rum, weil Code vor mir zu haben doch etwas anderes ist als wenn jemand stuecklesweise erzaehlt was er meint, dass der Code tun wuerde. ;-) Diese Erzaehlweise eignet sich in erster Linie dafuer, dass du selbst durch das Erklaeren deinen Fehler findest. Wenn du willst, dass wir ihn finden, dann solltest du dir ueberlegen uns doch eine bessere Informationsbasis bereitzustellen. (Ersetze notfalls alle Befehle, die nicht mit Imagemagick und den Dateien zu tun haben mit Auslassungszeichen.)

Oder debugge mal mit `strace -f -o trace=file,process' dann kannst du nachvollziehen was mit Dateien und den Prozessen passiert. (Bin mir nicht sicher ob die Optionen so richtig sind.)
Use ed once in a while!

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 21:03:28

@JTH: Da magst du Recht haben. Wir werden es nur erfahren, wenn dakuan uns die noetigen Einblicke bietet ...
Ich dachte, das es anhand der Code Auszüge klar ist, dass es sich um ein C-Programm handelt.

Das C-Programm hat etwa 1300 Zeilen. Da kommen dann noch die 3 Kommentarmodule dazu. Auszug aus Makefile:

Code: Alles auswählen

SRCS = ipic.c jpg_com.c png_com.c GIF_com.c
Der komplette Quelltext ist eigentlich auch nicht geheim, aber wo soll ich den hinladen?

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 25.05.2021 21:20:44

Meillo hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 20:50:07
@JTH:( oder feltel endlich mal die Glaskugeln fuer uns Mods bestellt :-P ).
Die war auch im Begrüßungspaket für die neuen Moderatoren leider nicht drin :| Ein bisschen Raten macht die Codeforensik doch erst spannend :)

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 20:49:33
Ich halte das jetzt schon für möglich. Was die Kommentareinfügefunktionen machen ist folgendes.

Die Originaldatei wird gelesen und gleichzeitig eine temporäre Datei erzeugt. Wenn das erfolgreich war, wird die Originaldatei gelöscht und die andere umbenannt.
Ja, das klingt nach der Ursache. display hat die Datei schon geöffnet (hat einen Filedeskriptor dafür), die Datei wird gelöscht und der Filedeskriptor zeigt damit ins Nichts. Er zeigt nicht automatisch auf die neue Datei mit selbem Name. Das kann je nach dem auch mal gutgehen, wenn display etwas langsamer dran ist und erst die neue Datei öffnet.

Meillo hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 21:00:05
Ist die Kommentarfunktion immer im Spiel oder ist die optional?
Das steht aber in den Codeschnipseln ;)

Code: Alles auswählen

    if ( strlen( rembuf ) ){ // Kommentar einfuegen lassen

Meillo hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 21:00:05
Zudem sollten mehr und schnellere Kerne das Starten von `display' beschleunigen und damit das Problem reduzieren.
Stimmt, das könnte den Fehler eigentlich seltener machen. Gleichzeitig sind aber ja Festplatten zu SSDs geworden, das könnte das vielleicht wieder umgekehrt haben.
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 25.05.2021 21:28:30

JTH hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 21:20:44
dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 20:49:33
Ich halte das jetzt schon für möglich. Was die Kommentareinfügefunktionen machen ist folgendes.

Die Originaldatei wird gelesen und gleichzeitig eine temporäre Datei erzeugt. Wenn das erfolgreich war, wird die Originaldatei gelöscht und die andere umbenannt.
Ja, das klingt nach der Ursache. display hat die Datei schon geöffnet (hat einen Filedeskriptor dafür), die Datei wird gelöscht und der Filedeskriptor zeigt damit ins Nichts. Er zeigt nicht automatisch auf die neue Datei mit selbem Name!
Der letzte Satz ist korrekt, die vorige Aussage aber nicht. Wenn eine Datei geoeffnet ist, dann gibt es einen Eintrag in der Open-File-Table im Kernel. Loeschen von Dateien ist in Unix ja unlink(2), d.h. es wird nur der Directory-Eintrag (aka Link) entfernt. Nur in dem Fall wenn es keine weiteren Hardlinks gibt und zudem die Datei auch nicht mehr geoeffnet ist, dann werden auch die Inode und die daran haengenden Datenbloecke freigegeben (d.h. ``geloescht''). Solange eine Datei noch geoeffnet ist, existiert sie weiterhin, auch wenn es keine Verzeichniseintraege mehr fuer sie gibt.

Konkret heisst das, dass `display' die Datei problemlos weiterhin anzeigen kann und auch neu darin lesen kann falls noetig, ungeachtet dessen, dass sie aus dem Dateisystem ``geloescht'' worden ist. Natuerlich -- und das sagt dein letzter Satz -- ist das die alte Version der Datei, diejenige zum Zeitpunkt des Oeffnens. Falls eine andere, neue Datei unter gleichem Namen abgelegt wird, dann bekommt diese `display' das nicht mit.
Use ed once in a while!

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 25.05.2021 21:39:34

Meillo hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 21:28:30
Der letzte Satz ist korrekt, die vorige Aussage aber nicht. Wenn eine Datei geoeffnet ist, dann gibt es einen Eintrag in der Open-File-Table im Kernel. Loeschen von Dateien ist in Unix ja unlink(2), d.h. es wird nur der Directory-Eintrag (aka Link) entfernt.
Tatsache, danke für die Korrektur! Irgendwie war ich mir bei der Aussage auch nicht 100% sicher. Ein Blick in die manpage hätte mir genau das verraten, was du schreibst:
man 2 unlink hat geschrieben: If the name was the last link to a file but any processes still have the file open, the file will remain in existence until the last file descriptor referring to it is closed.

Das würde aber wiederum die Erklärungsversuche für dakuans ursprüngliches Problem hinfällig machen. Das Kommentarhinzufügen ist damit quasi atomar und kann display nicht stören. Merkwürdig, dass ein Verschieben des display-Aufruf es trotzdem behoben zu haben scheint.
Manchmal bekannt als Just (another) Terminal Hacker.

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 25.05.2021 22:34:12

Konkret heisst das, dass `display' die Datei problemlos weiterhin anzeigen kann und auch neu darin lesen kann falls noetig, ungeachtet dessen, dass sie aus dem Dateisystem ``geloescht'' worden ist.
Das verunsichert mich jetzt wieder, zumal so etwas im oben genannten Buch auch erwähnt wurde. Vielleicht muss ich da doch noch länger testen.
Das Kommentarhinzufügen ist damit quasi atomar und kann display nicht stören.
Das rename ist tatsächlich atomar. Das hatte ich kürzlich in der Argumentation von
Thumbnail Saving (weiter bis: Concurrent Thumbnail Creation) gelesen. Aber das bezog sich nur auf gleichzeitiges schreiben.

Da muss ich wohl noch weiter forschen. 60 Tests sind da möglicherweise noch zu wenig.

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 25.05.2021 23:50:10

So direkt fällt mir dazu auch nichts mehr ein, da ein Datei-wird-gelesen-während-sie-überschrieben-wird durch das Verschieben ja anscheinend wegfällt.

dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 22:34:12
Da muss ich wohl noch weiter forschen.
dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 21:03:28
Der komplette Quelltext ist eigentlich auch nicht geheim, aber wo soll ich den hinladen?
Wenn du noch an einem zweiten oder dritten Paar Augen interessiert bist (und damit Meillo mangels Glaskugel nicht bald zu schwarzer Magie greift), kannst du deinen Code gerne nach NoPaste kopieren. Alle 1300 Zeilen müssen es vielleicht nicht direkt sein, aber ein deutlich größerer, zusammenhängender Ausschnitt des Ablaufs hier und eine der Kommentarfunktionen könnten helfen.
Manchmal bekannt als Just (another) Terminal Hacker.

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 26.05.2021 18:32:29

Alle 1300 Zeilen müssen es vielleicht nicht direkt sein, aber ein deutlich größerer, zusammenhängender Ausschnitt des Ablaufs hier und eine der Kommentarfunktionen könnten helfen.
Ok, ich versuche es mal. hier erstmal der Teil des Programms, der den Auftrag erstellt:
NoPaste-Eintrag41387

Und hier ein Kommentarmodul. Interessanst ist da die Funktion png_put_com():
NoPaste-Eintrag41388
p.s. der CRC Generator ist aus dem Buch: "Compressed Image File Formats" von John Miano.

JTH
Moderator
Beiträge: 3014
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: "race condition" bei Verwendung von system() ?

Beitrag von JTH » 26.05.2021 19:51:33

Am Rande: ImageMagick hat auch eine C-API – falls du mal zu viel Freizeit hast und die system() ersetzen willst ;)

Ansonsten: Ich nehme mal an, ENABLE_ALL_COM ist definiert? Falls nicht, dürfte der jhead-Aufruf das ursprünglich vermutete Problem auslösen, der überschreibt, was display versucht parallel zu lesen:

Code: Alles auswählen

    if ( strlen( rembuf ) ){ /* Kommentar einfuegen lassen */
        sprintf( workbuf, "jhead -cl \"%s\" \"%s\" > /dev/null", rembuf, img->name );
        system( workbuf );
    }

Andernfalls wäre meine nächste Vermutung, dass display versucht, die Datei zu lesen, wenn sie hier

Code: Alles auswählen

                remove( fname );
                rename( img_tname, fname );
im *_put_com() gerade gelöscht ist. In irgendeiner Form muss das ja basierend auf der ursprünglichen Fehlermeldung
dakuan hat geschrieben: ↑ zum Beitrag ↑
25.05.2021 16:25:45

Code: Alles auswählen

display-im6.q16: unable to open image `Traktor1.jpg': Datei oder Verzeichnis nicht gefunden @ rror/blob.c/OpenBlob/2701.
display-im6.q16: no decode delegate for this image format `' @ error/constitute.c/ReadImage/504.
der Fall sein.

Ich hab mal ein strace auf einen display-Aufruf laufen lassen. display öffnet (hier zumindest) die Datei insgesamt dreimal – und schließt sie auch zwischendurch wieder:

Code: Alles auswählen

$ strace -o strace.txt -e open,openat,stat,access,close display test.jpg
stat("test.jpg", {st_mode=S_IFREG|0600, st_size=20052, ...}) = 0
access("test.jpg", F_OK)             = 0
[…]
stat("test.jpg", {st_mode=S_IFREG|0600, st_size=20052, ...}) = 0
openat(AT_FDCWD, "test.jpg", O_RDONLY) = 4
close(4)                                = 0
[…]
stat("test.jpg", {st_mode=S_IFREG|0600, st_size=20052, ...}) = 0
openat(AT_FDCWD, "test.jpg", O_RDONLY) = 4
close(4)                                = 0
stat("test.jpg", {st_mode=S_IFREG|0600, st_size=20052, ...}) = 0
openat(AT_FDCWD, "test.jpg", O_RDONLY) = 4
close(4)
[…]
Neben einigen stat() und access()-Aufrufen. Das mehrfache Öffnen ist, vermute ich mal, zum anfänglichen Ermitteln des Dateityps (niemand verlässt sich auf Dateiendungen) und schließlich tatsächlichen Auslesen der Inhalte. Wenn die Datei bei einem der drei Öffnungsversuche gerade gelöscht ist, würde das zu obigem typischen

Code: Alles auswählen

Datei oder Verzeichnis nicht gefunden
passen.
Manchmal bekannt als Just (another) Terminal Hacker.

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 26.05.2021 20:51:23

Das mit dem C-API ist mir im Prinzip bekannt. Aber als ich mir das damals ansehen wollte, hatte ich irgendwie Probleme mit der Doku.

Heute würde ich das lieber mit eigenen Funktionen machen wollen. Ich benötige ja nur einfache Grundfunktionen. Gescheitert ist das bisher an den Schriften.
Ich nehme mal an, ENABLE_ALL_COM ist definiert?
Ja, die Verwendung von jhead ist eine Altlast. Und .PNG oder .GIF geht damit auch nicht.
display öffnet (hier zumindest) die Datei insgesamt dreimal – und schließt sie auch zwischendurch wieder:
Das vergrößert das Fehlerfenster natürlich deutlich, je nach dem wie lang die "Öffnungszeiten" jeweils sind. Ich habe strace nur einmal laufen lassen. Die Menge der Ausgaben hat mich umgehauen...
Das mehrfache Öffnen ist, vermute ich mal, zum anfänglichen Ermitteln des Dateityps
Normalerweise kann man das alles in einem Rutsch machen. Aber größere Programme sind ja meist modular aufgebaut. Dateityp prüfen wird ja auch benötigt, wenn man nur den Kommentar-Bereich lesen will. Im Beispiel wäre das:

Code: Alles auswählen

ReadSignature()
Ich könnte ja mal zum Testen ein anderes Programm zur Anzeige verwenden, vielleicht feh.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 27.05.2021 21:50:24

Wenn `display' die Datei mehrmals oeffnet kann das das Problem sein. Das sehe ich wie JTH. Warum `display' das jedoch tut erschliesst sich mir nicht, weil man, um die Datei mehrmals zu lesen, ja auch einfach rewind(3) nehmen koennte. Nun gut, so ist es halt.

Versuche ruhig mal `feh' oder `qiv' oder `sxiv' oder so (die letzteren zwei sind etwas minimalistischer). Wenn die die Datei nur einmal oeffnen, dann koennte das das Problem loesen.

Dass dich die Ausgabe von `strace' erschlaegt, wundert mich nicht. Das ist die Erfahrung jeder Person, die das Programm zum ersten Mal verwendet. ;-) Du musst dann halt geeignet auf einzelne Syscalls einschraenken oder in der Ausgabedatei effizient suchen.
Use ed once in a while!

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 27.05.2021 23:24:27

Warum `display' das jedoch tut erschliesst sich mir nicht, weil man, um die Datei mehrmals zu lesen, ja auch einfach rewind(3) nehmen koennte.
In gewisser Weise könnte ich das schon verstehen. Das könnte z.B. von der Schnittstelle der Funktion abhängen, Also wenn der Dateipfad übergeben werden muss oder ein gültiger Filepointer. Ich hatte z.B. schon den Fall, das ich in einem C++ Programm Daten von einer Datei brauchte, die ein bereits vorhandenes C-Programm liefern kann. Da ist dann allerdings die Schnittstelle eine andere.

Aber bei einem Programm "aus einem Guss" kann ich das auch nicht verstehen und versuche das zu vermeiden. Man kann das auch an meinem Beispielprogramm sehen, wo z.B. die Funktion png_get_size() (die im aktuellen Fall nicht verwendet wird) der Funktion ReadSignature() einen bereits vorhandenen File-Pointer übergibt.

Aber um die Gründe dafür zu ermitteln, möchte ich jetzt nicht in den Quelltext von 'display' einsteigen. Ich kämpfe schon genug mit dem Quelltext von FLTK um festzustellen, ob ein Fehler jetzt bei mir liegt oder ob es ein Bug ist (habe da schon 3 entdeckt, die inzwischen gefixt sind).

Also feh als Anzeigeprogramm wollte ich schon ausprobiert haben. Aber durch die Änderungen in den letzten Tagen, habe ich neue Probleme mit der Anordnung der Elemente, die allerdings keine Auswirkung auf das Problem haben, aber für mich eine höhere Priorität haben.
Dass dich die Ausgabe von `strace' erschlaegt, wundert mich nicht.
Das man da irgendwie filtern kann, war mir bisher nicht bekannt. Wenn ich wüsste, worauf man da triggern muss, könnte man den bisherigen Verdacht bestätigen oder wiederlegen. Problem ist da aber, das es ca. 10 bis 20 Versuche braucht, um das Problem zu provozieren.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: "race condition" bei Verwendung von system() ?

Beitrag von Meillo » 29.05.2021 09:16:52

dakuan hat geschrieben: ↑ zum Beitrag ↑
27.05.2021 23:24:27
Also feh als Anzeigeprogramm wollte ich schon ausprobiert haben. Aber durch die Änderungen in den letzten Tagen, habe ich neue Probleme mit der Anordnung der Elemente, die allerdings keine Auswirkung auf das Problem haben, aber für mich eine höhere Priorität haben.
Das finde ich vernuenftig. Melde dich einfach wieder wenn du dich erneut damit beschaeftigst.
Dass dich die Ausgabe von `strace' erschlaegt, wundert mich nicht.
Das man da irgendwie filtern kann, war mir bisher nicht bekannt. Wenn ich wüsste, worauf man da triggern muss, könnte man den bisherigen Verdacht bestätigen oder wiederlegen. Problem ist da aber, das es ca. 10 bis 20 Versuche braucht, um das Problem zu provozieren.
Du musst dir das Argument `-e' in der Manpage anschauen. Damit kannst du sagen welche Systemcalls du sehen willst. Wenn du `strace -e open' verwendest bekommst du nur alle Aufrufe von open(2) ausgegeben. Wenn du `strace -e trace=file' verwendest bekommst du alle File-bezogenen Systemcalls ausgegeben, das sind viele.

Sonst ist noch `-f' relevant. Wenn du das verwendest werden auch Kindprozesse getract, sonst nicht.

`strace' ist halt ein Hilfsmittel, das du einsetzen kannst um dem Problem auf die Spur zu kommen, weil es zeigt was wirklich passiert.
Use ed once in a while!

dakuan
Beiträge: 97
Registriert: 28.04.2011 22:09:39

Re: "race condition" bei Verwendung von system() ?

Beitrag von dakuan » 29.05.2021 18:47:43

Ich habe das jetzt mal mit feh und sxiv ausprobiert - Problem bleibt.

Code: Alles auswählen

feh WARNING: Traktor2.jpg does not exist - skipping
feh: No loadable images specified.
See 'man feh' for detailed usage information

Code: Alles auswählen

sxiv: Traktor2.jpg: No such file or directory
sxiv: No valid image file given, aborting
Zusätzlich habe ich auch mal ein eigenes Programm genommen, weil ich da weiß was es macht. Aber da ist nichts passiert. Dabei wird die Datei da auch zweimal geöffnet, einmal mit einer Bibliotheksfunktion um das Bild zu laden und danach von meinem Code um nach einem Kommentar zu suchen.

Verstehen tue ich das alles nicht. Wenn man davon ausgeht, das genau die Lücke zwischen remove() und rename() getroffen werden muss, sollt das Problem viel seltener auftreten.

Aber mit strace sollte ich mich wohl doch noch mal beschäftigen. Bei meinem ersten Versuch hatte ich das auf ein Grafisches Programm losgelassen. Da genügte eine Bewegung und der Bildschirm war vollgemüllt.

Antworten