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
- 1494 megtekintés
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
- A hozzászóláshoz be kell jelentkezni
Köszi a gyors választ! Ez elég rossz hír nekem. Valahogy nem lehet megakadályozni, hogy egy elkapott és kezelt signal felébressze a sleep-eket?
- A hozzászóláshoz be kell jelentkezni
Rakd be az usleep-et egy ciklusba, ami megnézi hogy letelt-e az idő, ha nem akkor visszaalszik.
- A hozzászóláshoz be kell jelentkezni
Igaz, hogy nanosleep, de az elv ugyanaz:
void nsleep(const struct timespec * sleep_time) {
struct timespec req,rem;
int status;
if (sleep_time==NULL)
return;
rem=*sleep_time;
do {
req=rem;
status=nanosleep(&req,&rem);
if (status==0 || status!=EINTR)
break;
} while (true);
}
- A hozzászóláshoz be kell jelentkezni
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?]
- A hozzászóláshoz be kell jelentkezni
Azért SIGIO, hogy tudjam kezelni a timeout-ot. A sima read() addig nem tér vissza, amíg nem érkezik adat, én pedig szeretném tudni, ha bizonyos ideje nem érkezett adat, vagyis a külsö eszköz nincs jelen.
- A hozzászóláshoz be kell jelentkezni
> 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.
- A hozzászóláshoz be kell jelentkezni
Biztos hogy ez nem valami szignált használ az időzítés megvalósítására? Mert szerintem igen.
- A hozzászóláshoz be kell jelentkezni
URL?
- A hozzászóláshoz be kell jelentkezni
Ez jó kérdés! Mert ha igen, akkor ez is zsákutca. :(
- A hozzászóláshoz be kell jelentkezni
Nem zsákutca, a kernel kezeli a timeout-ot. Itt van leírva, hogyan:
http://opengroup.org/onlinepubs/007908799/xbd/termios.html#tag_008_001_…
- A hozzászóláshoz be kell jelentkezni
- 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.
- 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.
- 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.
- A hozzászóláshoz be kell jelentkezni
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
- A hozzászóláshoz be kell jelentkezni
read() + select() es jo lesz, nem kell szignalozni...
- A hozzászóláshoz be kell jelentkezni
A szignálok nem alkalmasak szálak közötti kommunikációra. Van rá külön API, azt használd.
--
CCC3
- A hozzászóláshoz be kell jelentkezni
Köszi, de eddig sem szálak közötti kommunikációra akartam használni, hanem a soros port miatt jött be a képbe.
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni