Podle manuálové stránky open(2) můžete předat O_RDONLY|O_NONBLOCK nebo O_WRONLY|O_NONBLOCK abyste se vyhnuli open syscall bude zablokován (dostanete errno == ENXIO v tom případě)
Jak jsem uvedl, přečtěte si také manuálové stránky fifo(7) a mkfifo(3).
Nejprve několik přípravných zápasů:
Pomocí O_NONBLOCK a poll() je běžná praxe - ne naopak. Chcete-li úspěšně pracovat, musíte si být jisti, že zvládnete všechny poll() a read() návratové stavy správně:
read()návratová hodnota0znamená EOF -- druhá strana uzavřela spojení. To odpovídá (obvykle, ale ne ve všech operačních systémech)poll()vracíPOLLHUPobviňovat. Možná budete chtít zkontrolovatPOLLHUPpřed pokusem oread(), ale odread()to není nezbytně nutné zaručeně vrátí0po uzavření strany pro psaní.- Pokud zavoláte na číslo
read()než se připojí zapisovač a vy máteO_RDONLY | O_NONBLOCK, získáte EOF (read()vrací0) opakovaně, jak jste si všimli. Pokud však použijetepoll()čekat naPOLLINudálost před volánímread(), počká, až se zapisovač připojí, a nevytvoří EOF. read()návratová hodnota-1obvykle znamená chybu. Pokud všakerrno == EAGAIN, to jednoduše znamená, že momentálně nejsou k dispozici žádná další data a neblokujete, takže se můžete vrátit napoll()v případě, že je třeba manipulovat s jinými zařízeními. Pokuderrno == EINTRa potéread()bylo přerušeno před čtením jakýchkoli dat a můžete se buď vrátit napoll()nebo jednoduše zavolejteread()okamžitě znovu.
Nyní pro Linux:
- Pokud otevřete na straně čtení pomocí
O_RDONLY, pak:open()se zablokuje, dokud nebude otevřen odpovídající zapisovač.poll()dáPOLLINrevent, když jsou data připravena ke čtení nebo dojde k EOF.read()se zablokuje, dokud nebude načten požadovaný počet bajtů, spojení bude uzavřeno (vrátí 0), nebude přerušeno signálem nebo dojde k nějaké fatální IO chybě. Toto blokování poněkud maří účel použitípoll(), a protopoll()téměř vždy se používá sO_NONBLOCK. Můžete použítalarm()abyste se probudili zread()po určité době, ale to je příliš komplikované.- Pokud se zapisovač zavře, čtečka obdrží
poll()POLLHUPrevent aread()vrátí0poté na neurčito. V tomto okamžiku musí čtenář zavřít popisovač souborů a znovu jej otevřít.
- Pokud otevřete na straně čtení pomocí
O_RDONLY | O_NONBLOCK, pak:open()nebude blokovat.poll()dáPOLLINrevent, když jsou data připravena ke čtení, nebo dojde k EOF.poll()bude také blokovat, dokud nebude dostupný zapisovač, pokud žádný není přítomen.- Po přečtení všech aktuálně dostupných dat
read()buď vrátí -1 a nastavíerrno == EAGAINpokud je připojení stále otevřené, nebo vrátí0pokud je spojení uzavřeno (EOF) nebo ještě není otevřeno zapisovatelem . Kdyžerrno == EAGAIN, to znamená, že je čas vrátit se kpoll(), protože připojení je otevřené, ale nejsou k dispozici žádná další data. Kdyžerrno == EINTR,read()dosud nepřečetl žádné bajty a byl přerušen signálem, takže jej lze restartovat. - Pokud se zapisovač zavře, čtečka obdrží
poll()POLLHUPrevent aread()vrátí0poté na neurčito. V tomto okamžiku musí čtenář zavřít svůj popisovač souborů a znovu jej otevřít.
- (specifické pro Linux:) Pokud otevřete na straně čtení pomocí
O_RDWR, pak:open()nebude blokovat.poll()dáPOLLINrevent, když jsou data připravena ke čtení. U pojmenovaných kanálů však EOF nezpůsobíPOLLINneboPOLLHUPrevenuje.read()se zablokuje, dokud není přečten požadovaný počet bajtů, není přerušen signálem nebo se neobjeví jiná závažná IO chyba. U pojmenovaných kanálů nevrátíerrno == EAGAIN, ani nevrátí0jeden z. Bude tam jen sedět, dokud se nepřečte přesný počet požadovaných bajtů nebo dokud nepřijme signál (v takovém případě vrátí počet dosud přečtených bajtů, nebo vrátí -1 a nastavíerrno == EINTRpokud nebyly dosud načteny žádné bajty).- Pokud se zapisovač zavře, čtenář neztratí možnost číst pojmenované kanály později, pokud jiný zapisovač pojmenované kanály otevře, ale čtenář také neobdrží žádné upozornění.
- (specifické pro Linux:) Pokud otevřete na straně čtení pomocí
O_RDWR | O_NONBLOCK, pak:- Číslo
open()nebude blokovat. poll()dáPOLLINrevent, když jsou data připravena ke čtení. EOF však nezpůsobíPOLLINneboPOLLHUPreventy na pojmenovaných kanálech.- Po přečtení všech aktuálně dostupných dat
read()vrátí-1a nastavteerrno == EAGAIN. Nyní je čas vrátit se napoll()čekat na další data, případně z jiných streamů. - Pokud se zapisovač zavře, čtenář neztratí možnost číst pojmenované kanály později, pokud pojmenované kanály otevře jiný zapisovač. Připojení je trvalé.
- Číslo
Jak se správně obáváte, pomocí O_RDWR s trubkami není standardní, POSIX nebo jinde.
Protože se však zdá, že se tato otázka objevuje často, nejlepší způsob, jak v Linuxu vytvořit „odolné pojmenované kanály“, které zůstanou naživu, i když se jedna strana zavře, a které nezpůsobí POLLHUP odvrátí nebo vrátí 0 pro read() , je použít O_RDWR | O_NONBLOCK .
Vidím tři hlavní způsoby zpracování pojmenovaných kanálů v Linuxu:
-
(Přenosné.) Bez
poll()a s jedinou rourou:open(pipe, O_RDONLY);- Hlavní smyčka:
read()tolik dat, kolik je potřeba, případně smyčkování naread()hovory.- Pokud
read() == -1aerrno == EINTR,read()všechno znovu. - Pokud
read() == 0, spojení se ukončí a všechna data byla přijata.
- Pokud
-
(Přenosné.) S
poll()a s očekáváním, že kanály, a to i pojmenované, se otevřou pouze jednou a že jakmile jsou uzavřeny, musí je znovu otevřít jak čtenář, tak spisovatel, čímž se vytvoří nový kanál:open(pipe, O_RDONLY | O_NONBLOCK);- Hlavní smyčka:
poll()proPOLLINudálosti, případně na více potrubích najednou. (Poznámka:Toto zabráníread()od získání více EOF předtím, než se spisovatel připojí.)read()tolik dat, kolik je potřeba, případně smyčkování naread()hovory.- Pokud
read() == -1aerrno == EAGAIN, přejděte zpět napoll()krok. - Pokud
read() == -1aerrno == EINTR,read()všechno znovu. - Pokud
read() == 0, připojení je uzavřeno a musíte ukončit nebo uzavřít a znovu otevřít potrubí.
- Pokud
-
(Nepřenosné, specifické pro Linux.) S
poll()a s očekáváním, že pojmenované kanály nikdy neskončí a mohou být připojeny a odpojeny několikrát:open(pipe, O_RDWR | O_NONBLOCK);- Hlavní smyčka:
poll()proPOLLINudálosti, případně na více potrubích najednou.read()tolik dat, kolik je potřeba, případně smyčkování naread()hovory.- Pokud
read() == -1aerrno == EAGAIN, přejděte zpět napoll()krok. - Pokud
read() == -1aerrno == EINTR,read()všechno znovu. - Pokud
read() == 0, něco je špatně -- sO_RDWRby se to nemělo stávat na pojmenovaných kanálech, ale pouze sO_RDONLYnebo nepojmenované dýmky; označuje uzavřené potrubí, které musí být uzavřeno a znovu otevřeno. Pokud smícháte pojmenované a nepojmenované kanály ve stejnémpoll()smyčka zpracování událostí, může být tento případ stále potřeba zpracovat.
- Pokud