[megoldva] usleep vs signal - pthreads

Fórumok

Sziasztok!

Írok egy programot, ami több dolgot is csinál egyszerre, összesen 5 szálon (pthread). Ezek közül az egyik egy soros porti kommunikációt végez, amiben "Serial Programming HOWTO" 3.1 fejezetében levő példa alapján írt kód olvas-ír a soros portra. Ez:


saio.sa_handler = xt_signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO, &saio, NULL);
fcntl(xt_fd, F_SETOWN, getpid());
fcntl(xt_fd, F_SETFL, FASYNC);

Az a fura szituáció állt elő, hogy egy másik szál olyan műveletet végez közben, amiben fontos lenne, hogy pontosan (0.1 mp pontossággal) meg tudja adni, hogy mennyi ideig várakozzon. Na amikor megérkezik a soros porti szálhoz a signal, akkor az felébreszti a várakozó (pl. usleep(2200000);) szálat is. röviden az történik, hogy kommunikáció közben a várakozó szál hirtelen veszettül felgyorsul, így használhatatlanná válik a rendszer. Az világos számomra is, hogy a usleep() függvény addig alszik, amíg le nem telik az idő, amit megadtam neki, vagy nem érkezik egy signal, de nekem az nem világos, hogy a signal-ok kezelése miért van hatással más szálakra is!

Ha valakinek van ilyen irányú tapasztalata, akkor kérem segítsen nekem megoldani a problémát! Nyilván az én kódomban van valami hiba, de nem ástam magam mélyen bele a signal kezelés rejtelmeibe, csak amennyire muszáj volt.

Előre is köszönök minden építő jellegű hozzászólást!

Üdv:
denx

Hozzászólások

Rég volt már, de emlékeim szerinte signalok kezelése szigorúan process és nem szál szinten történik.

--
The Net is indeed vast and infinite...
http://gablog.eu

Nem értem. Ha egy arra kijelölt szál végzi a soros kommunikációt, akkor miért SIGIO*, miért nem szimpla read() ?

[*A SIGIO akkor lenne jó, ha 1 szál végezné az összes munkát (eseményvezérelt végrehajtás), nem?]

> Azért SIGIO, hogy tudjam kezelni a timeout-ot.

Akkor SIGALRM kéne, hogy a read() ne maradhasson blokkolva akármeddig. Soros kommunikációnál szerencsére beállítható a timeout, ami után a read() biztosan visszatér:

http://linux.die.net/man/3/tcsetattr

VTIME

Timeout in deciseconds for non-canonical read.

Szóval szignál helyett jobb a VTIME. Szerintem.

  1. Szignálok: a signal action processz-globális, a signal mask szál-lokális. Ha már szignálokat használsz, nem a sigprocmask()-ot kell használnod, mint egyszálú programban, hanem a pthread_sigmask()-ot. Mindenesetre szerintem ennél a feladatnál teljesen felesleges szignálokat használnod.
  2. Ha a read()-nél timeout-ot akarsz kezelni, akkor ne read()-et használj első körben, hanem például [p]select()-et, az egyszerre tud ugrani fd állapotra, timeout-ra, szignálra.
  3. Az usleep()-et felejtsd el. A legegyszerűbb szerintem erre is a select()-et használni. Ha nem nélkülözhetetlen a programodban a szignálkezelés, akkor -- különösen többszálú programban -- igyekezz a szignálokat minél nagyobb ívben kerülni, illetve (többszálú programban) mindazokat a függvényeket is, amelyeknek a doksi szerint lehet bármiféle bizonytalan kölcsönhatása a szignálokkal.

Köszi a segítséget! Megfogadom a tanácsaid (legalábbis egy részét):
1. Szignál helyett átírom a read()-et úgy, hogy a soros portnak legyen beállítva a timeout. (Ha ez nem jönne be, akkor áttérek a select()-es megoldásra.)
2. Kerülöm a szignálokat, csak itt kellett használjam, de valóban rendesen megszívatott, hogy "felébreszti" a sleep-elő szálakat. Megtanultam a leckét. :)
3. Mivel egyedül itt volt szignál a programomban, így egyelőre nem terveztem, hogy lecserélem a usleep()-eket, de ha továbbra is jönnek furcsaságok, akkor áttrek a select()-re itt is.

Mivel most azonnal nem tudom kioróbálni, ezért majd később jelentkezek az eredményekkel.

Még egyszer köszi!

Üdv:
denx

read() + select() es jo lesz, nem kell szignalozni...

A szignálok nem alkalmasak szálak közötti kommunikációra. Van rá külön API, azt használd.
--
CCC3

Köszönöm minden hozzászólónak az építő jellegű segítséget! Megint tanultam valamit! :)

Timeout-os read()-del (VTIME beállítva, signal handler kihajítva) megoldódott a probléma, de még a usleep() hívásokat is ki fogom cserélni a select-es megoldásra. Nem akarok egy ekkora risk-et benne hagyni a programban.