Du bist nicht angemeldet.

#1 08.03.2017 00:18:52

LessWire
Mitglied

Dateizugriff von anderen Prozessen

Hello to the C freaks!

Gibt es eine Funktion um für eine Datei zu erfahren, ob sie von anderen Prozessen noch geöffnet ist?

Gruß, LW

Beitrag geändert von LessWire (08.03.2017 23:11:51)

Offline

#2 08.03.2017 01:56:55

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

'man inotify' kenne ich natürlich - ob da ein file anderweitig im Zugriff ist, interessiert inotify nicht. In meinem Fall wird ein neu angelegtes file bereits gemeldet, obwohl es vom anderen Prozess (=postfix) noch gar nicht geclosed wurde - ja noch nicht mal der erste Datensatz zu lesen ist (Fehler bei fgets, paar usecs später klappts dann, mein Prozess läuft aber nur mit Prio 19). Ok, man kann mit usleep etwas warten - aber für einen Perfektionisten wie mich? Da iss das nix. smile

"lsof" Quellcode wäre natürlich einen Blick wert, war ich jetzt noch zu faul. sad
Wahrscheinlich ist meine jetzige Lösung durchaus performant genug, ich dachte halt, evtl. hat jemand einen schnellen Vorschlag wie z.B. "if (file_in_use(filename)) ..." - also eine von mir übersehene Funktion. wink

Danke + Gruß, LW

Beitrag geändert von LessWire (08.03.2017 01:58:37)

Offline

#3 08.03.2017 08:22:08

T.M.
Mitglied

Re: Dateizugriff von anderen Prozessen

open? fopen?

Du kannst dabei noch steuern, ob Du den Lese- oder Schreibmodus eines anderen testen willst. Wenn ein anderer liest, kannst Du nicht darin schreiben. Wenn ein anderer schreibt, kannst Du weder darin schreiben noch lesen.

Der Test mit open ist übrigens vorteilhaft. Wenn das gelingt, ist die Datei auch automatisch offen, d.h. für Dich gelockt. Ein anderer kann nicht dazwischenfunken. Wenn Du hingegen zum Test einen Aufruf machst, der die Datei nicht sofort öffnet, dann kann in der nächsten Millisekunde einer kommen und Deinen Test obsolet machen. (Ich würde das nicht sagen, wenn es nicht tatsächlich so passieren würde ...) Du musst ja übrigens nicht schreiben, wenn's nichts zu schreiben gibt. Dennoch kannste im Schreibmodus öffnen, um ein exklusives Lock zu bekommen.

Offline

#4 08.03.2017 14:44:52

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

@T.M.: So sollte es sein - nicht aber in meinem Fall. sad

Zum besseren Verständnis folgender Code mit dem Wesentlichen:

#define EVT_SIZE  ( sizeof (struct inotify_event) )
#define EVT_LEN   ( 1024 * ( EVT_SIZE + 16 ) )

int main() {
	int fd;
	if ( (fd=inotify_init()) < 0 ) perror("inotify_init");

	int wd = inotify_add_watch(fd, "/DirToWatch", IN_CREATE);
	if (wd < 0) perror( "inotify_add" );

	char sEVT[EVT_LEN];
	struct inotify_event *pI=(struct inotify_event *)sEVT;
	while (1) {
		int len = read( fd, sEVT, EVT_LEN ); // wait for event
		if ( len > -1 ) {
			// !!! fopen klappt, obwohl ganz offensichtlich vom anderen Prozess noch
			// im Schreibzugriff:
			FILE *F=fopen("NewCreatedFile", "r");
			if (F == NULL) return;

			char Line[maxsize];

			// !!! ugly workaround:
			// Warten, bis anderer Prozess in "NewCreatedFile" geschrieben hat und
			// fgets dann erfolgreich wird ("i" vermeidet mögliche Endlosschleife falls Datei tatsächlich leer)
			int i=0;
			while (fgets(Line, maxsize, F) == NULL && i<10) { usleep(50); i++; }
			// !!! end of the "ugly" ;)

			do {
				// ... some procedures not shown here
			} while (fgets(Line, maxsize, F) != NULL);

			fclose(F);
		}
	}

	close (fd);
	return 0;

Es ist korrekt, wenn inotify mit "IN_CREATE" sofort reagiert, sobald ein neues file lediglich geöffnet wird - aber der Zugriff auf dieses mit Schreibrecht geöffnete File (write lock) sollte dann nicht möglich sein.

Obwohl meine Testdatei mit 4 kurzen Zeilen nur wenige Bytes gross ist, tritt das beschriebene Verhalten beim Kopieren dieser Datei ins überwachte Verzeichnis auf. Das Programm "überholt" somit das noch nicht abgeschlossene 'cp' aus der shell - trotz niedrigerer Prozesspriorität.

Dieser Thread von mir ist eigentlich unsinnig, denn die "gesuchte" Funktion ist mir ja auch bereits bekannt (open etc.). Das Verhalten in diesem Fall hat mich nur zunächst etwas verwirrt, also sorry!

Es sieht eher danach aus, die Problematik in der kernel community zu diskutieren.

Beitrag geändert von LessWire (08.03.2017 14:57:36)

Offline

#5 08.03.2017 23:08:00

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

Console 1: cat >test

"test" ist angelegt und open zum Schreiben.

Console 2: cat >test

Klappt problemlos

Console 1: T1 eingetippt
Console 2: T2 eingetippt
Console 1: file closed
Console 2: file closed

Inhalt der Datei: T2

Eigentlich sollte ja ein bereits zum Schreiben geöffnetes file nicht ein 2.tes Mal geöffnet werden können - ist aber offensichtlich so.

Edit:
Das notwendige locking muss man mit 'flock' selbst bewerkstelligen. Evtl. dann auch eine Lösung für mein eigentliches Problem, vermutlich müsste aber das andere Programm dafür sorgen.

Beitrag geändert von LessWire (08.03.2017 23:33:31)

Offline

#6 09.03.2017 07:51:59

T.M.
Mitglied

Re: Dateizugriff von anderen Prozessen

TBone schrieb:
T.M. schrieb:

Du kannst dabei noch steuern, ob Du den Lese- oder Schreibmodus eines anderen testen willst. Wenn ein anderer liest, kannst Du nicht darin schreiben. Wenn ein anderer schreibt, kannst Du weder darin schreiben noch lesen.

Wie geht das?
Mir ist das völlig neu, in man 3 open habe ich nichts gefunden ein kleiner Test eben hat etwas anderes ergeben. (Verhalten nicht gesteuert wie beschrieben, da ich ja nicht weiß wie)

Die Funktion open() hat zwei überladene Prototypen:

int open(char * filename, int flags)
int open(char * filename, int flags, int mode)

(vergl. z.B. hier: http://rabbit.eng.miami.edu/info/functions/unixio.html )

Du kannst (und in sauberem C oder C++ musst Du sogar zwingend) beim Aufruf flags mitgeben, um zu steuern, wie die Datei geöffnet werden soll. O_RDONLY erlaubt Dir nur Leseoperationen, O_WRONLY erlaubt Dir nur Schreiboperationen und O_RDWR erlaubt beides. Der andere benutzt ebenfalls auf irgendeine Art diese Steuerungsmöglichkeiten, um die Datei zu öffnen. Das Betriebssystem stellt dann sicher, dass nur einer in die Datei schreiben kann. Schreibzugriff gibt's ausserdem nur dann, wenn keiner zuvor die Datei zum Lesen geöffnet hat. Lesen können ggf. mehrere, solange nicht einer zuvor erfolgreich die Datei zum Schreiben öffnen konnte.

Offline

#7 09.03.2017 08:14:14

T.M.
Mitglied

Re: Dateizugriff von anderen Prozessen

LessWire schrieb:

Es ist korrekt, wenn inotify mit "IN_CREATE" sofort reagiert, sobald ein neues file lediglich geöffnet wird - aber der Zugriff auf dieses mit Schreibrecht geöffnete File (write lock) sollte dann nicht möglich sein.

Ich kann mir nicht vorstellen, dass das tatsächlich möglich ist. Woran ist den zu erkennen, dass die Datei noch geschrieben wird, während Du sie schon zum Lesen öffnen kannst?

Ich vermute etwas anderes: Es gibt relativ oft (z.B. bei log files) die Situation, dass einer eine Datei zunächst erst einmal anlegt, damit sie vorhanden ist, d.h. damit ihr Name festliegt. Dann macht er sie zu und tut etwas anderes. Und dann, später, öffnet er sie und schreibt etwas hinein. Man muss ja auch folgendes sehen: das Schliessen einer Datei ist gleichbedeutend mit dem endgültigen Leeren der Schreibpuffer. Wer wirklich zu einem gegebenen Zeitpunkt sicherstellen muss, dass alles in die Datei geschrieben worden ist, muss sie flushen oder schliessen. Wahrscheinlich kommst Du auch in eine solche Phase, in der die Datei zwischenzeitlich mal geschlossen ist. Deshalb gelingt das Öffnen zum Lesen. (Wenn das allerdings so ist, kann der andere Prozess die Datei dann nicht zum Schreiben öffnen ...)

Bei solchen Sachen, es handelt sich ja letztendlich um eine primitive Form von Interprozesskommunikation, muss man manchmal sleeps u.ä. einbauen, um dem anderen bisschen Zeit zu geben, insbesondere wenn man nicht genau weiss, wie er vorgeht. Und man muss drauf achten, dass man ihn nicht dauerhaft blockiert, d.h. Du solltest, wenn Du nichts lesen kannst, die Datei umgehend schliessen, dann bisschen warten und sie dann wieder neu öffnen. Machste ja, allerdings ist das Lesen der Datei bei Dir von dem event abhängig, und das kommt später nicht mehr, es kommt ja nur, wenn eine Datei neu erstellt wird. Ich würde dieses event benutzen, um nur die while-Schleife zu starten. Diese sollte aber das Lesen der Datei dann unbedingt durchführen, solange diese existiert, und in jedem Schleifendurchlauf ein sleep() stehen haben. Das wäre die einfachste Variante, die Datei quasi pollen. Eleganter wäre die Reaktion jeweils auf ein event, das durch IN_MODIFY oder IN_CLOSE_WRITE ausgelöst wird.

Beitrag geändert von T.M. (09.03.2017 08:25:17)

Offline

#8 10.03.2017 10:30:25

T.M.
Mitglied

Re: Dateizugriff von anderen Prozessen

Es ist in der Tat nicht so. Im folgenden ...

int fd1 = open("textfile", O_WRONLY);
int fd2 = open("textfile", O_WRONLY);

... hätte ich geschworen, fd2 darf keinen handle bekommen, tut es aber, d.h. es können tatsächlich zwei in dieselbe Datei schreiben. Es gelingt auch mit fopen() und sogar mit fstreams. Man lernt nie aus.

Bei Microsoft gibt's die Funktion sopen(), die die Angabe eines file-sharing-Parameters erlaubt. Bei gcc scheint diese nicht vorhanden zu sein. Dort muss man offenbar nach open() noch zusätzlich flock() benutzen, das es wiederum bei MS nicht gibt. Das ist allerdings Mist, weil es in zwei Funktionsaufrufen geschieht, wo wieder von aussen einer dazwischen kommen kann. Und dann besteht ja noch das Problem, dass diese Funktionen auch benutzt werden müssen, d.h. man kann sich bei einem fremden Prozess nicht drauf verlassen.

Offline

#9 10.03.2017 22:03:21

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

Warum sollte es sich auch anders verhalten, als ich es oben mit den "cat" Kommandos schon angedeutet hatte. wink

Ich finde dieses Verhalten aber mittlerweile durchaus als akzeptabel: der Programmierer entscheidet selbst, ob ein file lock Sinn macht. In den meisten Fällen wohl eher nicht - wann greifen schon mehrere Prozesse gleichzeitig auf dieselbe Datei (schreibend) zu? Generelle file locks würden doch nur unnötig das System 'bremsen'.

Mein oben beschriebener Fall ist da ein Sonderfall:
'inotify' mit CREATE flag ist halt einfach zu schnell und ein passenderes flag gibt's für meinen Fall nicht. Aber soll deshalb jedes Programm bei Schreibzugriffen generell mit file locks arbeiten? Lieber nicht. wink

Schönes Wochenende und Gruß, LW.

Offline

#10 10.03.2017 23:10:26

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

TBone schrieb:
LessWire schrieb:

Warum sollte es sich auch anders verhalten

Folgender Ablauf von Programm P1 und P2.

P1 öffnet x.txt RW
P2 öffnet x.txt RW
P1 lockt x.txt exklusiv (flock/lockf/fcntl)
P1 schreibt in die Datei: Return Erfolgreich
P2 schreibt in die Datei: Return Erfolgreich
P1 gibt den Lock auf
P1 schließt die Datei
P2 schließt die Datei

Es steht der Inhalt von P2 in der Datei, nicht der von P1, ein Lock ist kein Lock, ich bin hier voll bei T.M., es wäre schöner, wenn man mit open direkt locken könnte. (Könnte, nicht muss)

Nachdem beide Prozesse bereits open ausgeführt haben und dann erst der lock erfolgt, würde ich das Verhalten mal noch als normal bezeichen. Weil: einfach schlecht, wenn P2 von bereits erreichten Rechten nachträglich etwas abgeben müsste - zu diesem Zeitpunkt wäre der Zug schon abgefahren.

Was passiert, wenn es so abläuft:

P1 öffnet x.txt RW
P1 lockt x.txt exklusiv (flock/lockf/fcntl)
P2 öffnet x.txt RW
...

Dann sollte P2 doch die 'A....-Karte' gezogen haben - andernfalls wäre das alles wirklich sinnlos (was ich mir nicht vorstellen kann).

Edit:
Wie du sagst, lock als flag beim open wäre natürlich ideal, weil vor allem auch der richtige Zeitpunkt. Man weiß ja nicht, ob z.B. der task scheduler zwischen openund lock auch noch dazwischen funkt und im Extremfall zu üblen Effekten führen kann (race).

Edit2: Heute (1 Tag später) nochmal recherchiert und siehe da: "flopen" macht das, was wir uns vorstellen.

Beitrag geändert von LessWire (11.03.2017 22:46:37)

Offline

#11 12.03.2017 10:47:48

T.M.
Mitglied

Re: Dateizugriff von anderen Prozessen

LessWire schrieb:

Was passiert, wenn es so abläuft:

P1 öffnet x.txt RW
P1 lockt x.txt exklusiv (flock/lockf/fcntl)
P2 öffnet x.txt RW
...

Dann sollte P2 doch die 'A....-Karte' gezogen haben - andernfalls wäre das alles wirklich sinnlos (was ich mir nicht vorstellen kann).

Das Problem ist, daß der Zugriff durch den zweiten Prozeß so schnell gehen kann, daß ersterer gar nicht mehr die Möglichkeit hat, sein lock sinnvoll anzuwenden. Das ist inbesondere dann der Fall, wenn der zweite Prozeß automatisch auf ein Ereignis im Dateisystem reagiert, beispielsweise auf das Anlegen einer Datei. Deshalb muß das Öffnen (bzw. Anlegen) einer Datei zeitgleich mit ihrem locking geschehen, das muß eine atomare Operation sein, die also tief unten ununterbrechbar durchgeführt wird. Zwei getrennte Funktionsaufrufe weiter oben sind kein guter Weg und wenn immer möglich zu vermeiden.

Edit2: Heute (1 Tag später) nochmal recherchiert und siehe da: "flopen" macht das, was wir uns vorstellen.

Ich wäre nicht überrascht, wenn es noch mehr (insbesondere proprietäre) Funktionen gäbe. Mich wundert hingegen viel mehr, daß das beim klassischen open() keine Rolle spielt. Zu verhindern, daß zwei in eine Datei schreiben, ist doch ein Problem, das so alt ist wie Multitasking selber. Ferner gibt's auch bei modernen C++ streams (ofstream, ifstream) offenbar keine Möglichkeit, ein standardisiertes, plattformunabhängiges file locking zu machen. Das überrascht mich wirklich sehr.

Offline

#12 12.03.2017 13:12:42

portix
Mitglied

Re: Dateizugriff von anderen Prozessen

LessWire schrieb:

Was passiert, wenn es so abläuft:

P1 öffnet x.txt RW
P1 lockt x.txt exklusiv (flock/lockf/fcntl)
P2 öffnet x.txt RW
...

Dann sollte P2 doch die 'A....-Karte' gezogen haben - andernfalls wäre das alles wirklich sinnlos (was ich mir nicht vorstellen kann).

Genauso ist es aber, ein flock hindert andere Prozesse nicht daran in die Datei zu schreiben, ist so auch unter man flock dokumentiert, flock verhindert nur, dass eine anderer Prozess einen lock auf die Datei erhalten kann. flopen ändert das auch nicht sondern sichert nur zu, dass sich die Datei zwischen den Aufrufen von open und flock nicht geändert hat. Ein anderes Programm kann den Dateilock trotzdem ignorieren.

Beitrag geändert von portix (12.03.2017 13:13:32)

Offline

#13 12.03.2017 21:54:45

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

@T.M. @portix: tks for info!
Wenn sich das mit 'flopen' selbst mit exclusive flag so verhält (ich kam bisher nicht weiter zum Testen und glaube Euch natürlich) - klar, so sollte es nicht sein.
Das wissen aber die Kernelentwickler doch nicht erst seit gestern. Ich klinke mich aber aus dem thread mal aus - bei meinen Aufgaben hab' ich es bisher noch nicht gebraucht bzw. ein workaround war einfach. wink

Gruß, LW.

Beitrag geändert von LessWire (12.03.2017 21:56:17)

Offline

#14 13.03.2017 23:05:46

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

TBone schrieb:

Macht es nicht, nutze mal strace:

Das weiß ich inzwischen (siehe vorausgegangene Beiträge). wink

Offline

#15 13.03.2017 23:45:49

LessWire
Mitglied

Re: Dateizugriff von anderen Prozessen

Ok, im Detail hast Du natürlich recht. Mir haben die Ausführungen von portix diesbezüglich genügt.

Offline

Schnellantwort auf dieses Thema

Schreibe deinen Beitrag und versende ihn
Deine Antwort

Fußzeile des Forums