Zajímalo by mě, jestli systémová volání linuxu pro čtení/zápis podporují synchronizované čtení/zápisy (bez připojování) do nepřekrývajících se oblastí jednoho souboru na disku z více vláken nebo procesů. Každé vlákno bude hledat svou vlastní oblast souboru a bude číst/zapisovat výhradně z/do této oblasti, přičemž nikdy nebude překrývat oblasti, na kterých pracují jiná vlákna.
POSIX specifikuje v XSH 2.9.7, že v podstatě všechny I/O funkce jsou atomické, pokud jde o jejich účinky specifikované POSIX. Je uveden dlouhý seznam konkrétních funkcí, kterých se to týká, a open()
, lseek()
, read()
, write()
a close()
jsou na tom všichni. Proto,
Pokud dvě vlákna volají jednu z těchto funkcí, každé volání buď uvidí všechny zadané efekty druhého volání, nebo žádný z nich.
To nezávisí na žádné externí synchronizaci, a to ani pro operace s deskriptory souborů souvisejícími se stejným popisem otevřeného souboru.
Může existovat více popisů otevřených souborů pro stejný soubor, dokonce i v jednom procesu (viz například manuálová stránka pro open(2)). Zadáno několik vláken s výkonem read()
a write()
operace s nepřekrývajícími se oblastmi stejného běžného souboru prostřednictvím deskriptorů souborů odkazujících na různé popisy otevřených souborů POSIX neposkytuje žádný základ pro to, abychom očekávali, že se tyto operace budou vzájemně ovlivňovat, bez ohledu na externí synchronizaci zúčastněných vláken. V praxi to funguje dobře.
Kde se můžete dostat do problémů je, pokud se zúčastněná vlákna pokoušejí použít deskriptory souborů odkazující na stejný popis otevřeného souboru. Nemusí se jednat o stejnou hodnotu deskriptoru souboru (takže dup()
Zde nepomůže zadání deskriptoru souboru), ani vlákna nemusí patřit do stejného procesu, aby situace nastala. Každý otevřený popis souboru má jednu přiřazenou pozici souboru, takže pokud se dvě různá vlákna pokoušejí provést úkoly, každé vyžaduje samostatně nastavení offsetu souboru a přenosu dat do souboru nebo ze souboru a pokud používají stejný popis otevřeného souboru, pak atomicita volání jednotlivých funkcí není dostatečná k tomu, aby zajistila, že čtení a zápis budou provedeny na zamýšlených pozicích. V tomto scénáři je vyžadována synchronizace.
Alternativně, jak poznamenal @maximegorushkin v komentářích a @bk2204 v jiné odpovědi, pread()
a pwrite()
funkce provádějí určování polohy a přenos dat v jediném volání. Jsou také na seznamu atomických I/O funkcí a překonávají oddělení určování polohy od přenosu dat na bázi přenosu dat. Jejich použití vyžaduje zvláštní péči a vedení účetnictví a existují scénáře, že nedostatečně poslouží, ale přesto může být v konkrétním případě životaschopné.
Proto , pokud dvě různá vlákna chtějí pracovat se stejným souborem bez synchronizace, pak nejbezpečnějším a nejobecnějším přístupem je otevřít soubor nezávisle pro každé z nich. Pak se nebudou vzájemně ovlivňovat, pokud jsou jejich I/O operace omezeny na nesouvislé oblasti souboru. Dokonce i operace s překrývajícími se oblastmi souboru není vyloučena, ale to přináší složitější úvahy specifické pro aplikaci.
Ano, je to možné. pread
a pwrite
funkce umožňují číst a zapisovat ze souboru s daným posunem bez změny posunu souboru. Jsou speciálně navrženy tak, aby umožňovaly čtení a zápis ve vícevláknových programech.
Měli byste si uvědomit, že v rozporu s POSIX, pwrite
na deskriptoru souboru otevřeném O_APPEND
bude vždy zapisovat na konec souboru.