|
|
Lze oživit vlákno zablokované na read()?
|
27.11.2007 01:13
Jan Němec
|
Píšu v C malý servřík, mám vše v jednom procesu (žádné fork, exec), používám vlákna (pthread_create) a sockety. Hlavní vlákno většinu času spí na accept(), vlákno obsluhující klienta spí na read(), používám totiž blokovací režim socketu, ktery mi vyhovuje. Pak mám ještě ovládací vlákno, které server řídí.
A teď problém. Řídící vlákno usoudí, že vlákno klienta má 1) ukončit ten zablokovaný read() a 2) hlavní vlákno accept(). Samozřejmě nechci ta vlákna odbouchnout, chci jen aby read a accept skoncily s chybou a vlakno dal jelo.
add 1) Jde to vubec nejak? Nebo to musim obchazet pres neblokovaci rezim a select a pomocny file descriptor typu pipa, kterym ten select probudim.
add 2) Jde to nejak elegantneji nez close(socket) a poslanim signalu sam sobe?
Diky moc za pripadne rady, fakt jsem to nevygooglil. |
|
|
Re: Lze oživit vlákno zablokované na read()?
|
27.11.2007 01:52
Aleš Hakl
|
Prakticky vsechna systemove volani, ktera se umeji zablokovat lze prerusit. A to zaslanim signalu, ktery ma nejakou obsluznou funkci. Ovsem je to spise takovy implementacni detail obsluhy signalu a napriklad SUSv3 toto specifikuje dosti nejasne (nikde neni receno jestli to funguje vzdy). Je to elegantni treba na niceni zombie procesu ve smycce accept()-fork() nejakeho serveru (tj. na neco, kde kdyz to nefunguje nicemu az tak moc nevadi).
Pokud o to nejak zajimave jde, tak bych asi pouzil ten neblokujici rezim a select().
Vzhledem k tomu, ze stejne neni dobry napad mit v programu nejake nahodne vyskyty volani typu read() a write(), tak bych si napsal wrapper, ktery bude nad neblokujicim socketem emulovat blokujici read() (pomoci nejakeho select() nebo poll()) + osetrovat stavy typu "read vratil EINTR". |
|
|
Re: Lze oživit vlákno zablokované na read()?
|
27.11.2007 08:35
Jan Němec
|
Díky za odpověď.
Tak jsem to nakonec napsal s tou pípou. Funguje to, ale vůbec se mi to nelíbí. Pokud se najde nějaký linuxový C machr, budu vděčný za připomínky.
Takhle jsem to napsal:
// Vlákno čtení od klienta
while (1) {
char c;
fd_set r;
FD_ZERO(&r);
FD_SET(fd, &r);
FD_SET(pipa[0], &r);
select((fd > pipa[0] ? fd : pipa[0]) + 1, &r, NULL, NULL, NULL);
if (FD_ISSET(pipa[0], &r)) break;
if (read(fd, (void *)&c, 1) != 1) break;
// tady něco dělám s tím bytem
}
// Vlakno koncici cyklus cteni
close(fd);
char nejakej_byte = 0;
write(pipa[1], (void *)&nejakej_byte, 1);
Místo aby to šlo prostě takhle:
// Vlákno čtení od klienta
while (1) {
select((fd > pipa[0] ? fd : pipa[0]) + 1, &r, NULL, NULL, NULL);
// tady něco dělám s tím bytem
}
// Vlakno končící cyklus čtení
close(fd); // Nefunguje!!! Volání close neukončí zablokovaný read.
|
|
|
Re: Lze oživit vlákno zablokované na read()?
|
3.12.2007 13:13
Tomáš "Atom" Klas
|
Zkuste nejprve shutdown() a potom close(). Může to pomoci, ale nespoléhal bych se na přenositelnost.
Také by mohlo pomoci místo select() použít poll() s flagem POLLHUP. Bohužel poll() je čistě Linuxové volání, ale zase mnohem lépe řešené než select().
Obávám se, že řešení s pipe() je jediné spolehlivé.
|
|
|
Re: Lze oživit vlákno zablokované na read()?
|
4.12.2007 13:39
Oldrich Pikhart
|
Pokud vim, tak poll() neni ciste Linuxova vec viz.:
http://www.opengroup.org/onlinepubs/009695399/functions/poll.html
Linuxova vec je tusim az epoll. |
|
|
Re: Lze oživit vlákno zablokované na read()?
|
7.5.2010 09:28
Jan Němec
|
Díky za radu s tím shotdownem. Náhodou jsem po 2 a půl letech řešil stejný problém. Portoval jsem nějakou C++ knihovnu z iPhone na Android. Na iPhone to close odblokovalo spící recvfrom, ale na Androidu ne. Zkusil jsem to shutdown a zabralo to. Ušetřil jste mi pípování. |
|
|
|
|
KOMENTARZE
|
Tylko zarejestrowani użytkownicy mogą dopisywać komentarze.
|
|
Szukanie oprogramowania
|
©Pavel Kysilka - 2003-2024 |
maillinuxsoft.cz | Design:
www.megadesign.cz
|