Portál AbcLinuxu, 4. května 2025 10:39
Jednoduché je to v případech, kdy máme k dispozici souborové deskriptory. Ty použijeme ve volání select(), poll() nebo epoll() a hned se dozvíme, co se stalo. Problém je ovšem v tom, že tyto deskriptory máme jen pro omezený okruh událostí. Pro mnohé události (asynchronní I/O, časovače, skončení podřízeného procesu atd.) musíme spoléhat na signály - a ty s výše uvedeným nejdou příliš dohromady.Ad asynchronní I/O a deskriptory - píšeš, že jediným skutečně bezpečným způsobem zpracování signálů je volání
sigwait()
. Co je špatně na způsobu, kdy se při zpracování signálu SIGIO pomocí select()
otestují deskriptory a příslušně se zareaguje? (Za předpokladu, že deskriptorů není příliš mnoho)
sigwait()
(a samozřejmě také sigwaitinfo()
a sigtimedwait()
) má tu výhodu, že se zpracuje vždy právě jeden signál (a ostatní zůstávají blokované) a nepoužívá se - není potřeba - asynchronní handler. Při jiném řešení už nastávají komplikace s rozlišováním, které všechny signály vlastně přišly. Tak jako tak tam ale zůstane problém s výkonností, protože select/poll operace je obecně O(n).
int main() { struct sigaction sigakce; void io_sigio (int i); void casovano (int i); ... sigakce.sa_handler = io_sigio; sigfillset (&sigakce.sa_mask); sigakce.sa_flags = 0; sigaction (SIGIO, &sigakce, NULL); sigakce.sa_handler = casovano; sigaction (SIGALRM, &sigakce, NULL); for (;;) {pause();} }Program má jenom reagovat na události - příchod dat ze sítě a periférií a na časovač, takže čeká v nekonečné smyčce. Jestli jsem to dobře pochopil, tak při použití
sigwait()
by program v nekonečné smyčce volal tuto funkci a rozhodoval, jaký signál přišel a jak se zachovat.
Při jiném řešení už nastávají komplikace s rozlišováním, které všechny signály vlastně přišly.To znamená, že když nepoužívám sigwait() a přijde víc signálů najednou, že se některé zahodí a nezpracují? Já měl zato, že se nejprve zavolá obsluha jednoho a pak druhého.
Tak jako tak tam ale zůstane problém s výkonností, protože select/poll operace je obecně O(n).Jasně, proto jsem psal, že předpokládám, že deskriptorů je málo (tento případ rozhodně není to, co je popsáno v blogu - tj. server s mnoha síťovými spojeními, otevřenými soubory apod.)
volatile
(= rychlost dolů). A tak dále.
Jestli jsem to dobře pochopil, tak při použití sigwait() by program v nekonečné smyčce volal tuto funkci a rozhodoval, jaký signál přišel a jak se zachovat.
sigwait()
vrací (resp. zapisuje přes pointer) číslo signálu, který přišel. Funkce sigwaitinfo()
a sigtimedwait()
dělají totéž, ale navíc ještě poskytují další informace (např. identifikátor časovače, PID ukončeného potomka, PID procesu, který zavolal kill()
apod.).
Všechny tyto funkce fungují tak, že se zavolají s blokovanými signály, tyto se uvnitř odblokují, a když přijde první signál (nebo už nějaký čeká), zase se všechny signály zablokují a vyskočí to ven z funkce. To vše atomicky. Pak lze bezpečně a synchronně dělat cokoliv. Takže se to používá tak, že se v nekonečné smyčce volá sigwait()
a vždy se podle čísla signálu zjistí, jaká událost nastala.
To znamená, že když nepoužívám sigwait() a přijde víc signálů najednou, že se některé zahodí a nezpracují? Já měl zato, že se nejprve zavolá obsluha jednoho a pak druhého.Signál se "zahodí" jen v jediném případě - že se jedná o obyčejný (klasický POSIXový, ne-realtime) signál a již nějaký čeká na zpracování. Ovšem když přijde více signálů "najednou" (tedy těsně po sobě), začne se zpracovávat jeden, a pokud ty další nejsou blokované, může kdykoliv začít obsluha jiného (s jiným číslem). Takže to doběhne třeba do půlky handleru a v tu chvíli začne obsluha jiného signálu. Blokace v handleru to úplně neřeší, protože se nemusí stihnout (i když toto není většinou tragédie). Horší ale je, že jsou to pro každý handler 2 syscally navíc, což sežere dost času. Tohle je výhoda
sigwait()
, že takové problémy se nemusejí vůbec řešit.
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.