Kirjoittaja Aihe: select()  (Luettu 3319 kertaa)

satsuma

  • Käyttäjä
  • Viestejä: 63
    • Profiili
select()
« : 28.07.06 - klo:09.18 »
Osaiskohan joku vähän valaista, että
miten tuo select() -funktio c-ohjelmoinnissa
oikein käytännössä toimii? Olen lukenut
man sivuja ja etsinyt netistä, mutta
en oikein löydä käytännön esimerkkiä
mistään.

Eli, jos ohjelmassani on 10 putkea,
joista olisi tarkoitus lukea dataa,
ja selelect() ilmoittaa, että kolmessa
on dataa valmiina, niin mistä tiedän
missä niistä? Täytyykö käydä kaikki
läpi järjestyksessä?

Olen tehnyt pienen ohjelman, jossa
select() funktiolla odotetaan dataa
kolmeen putkeen. Ohjelma on
suurinpiirtein seuraavanlainen

Koodia: [Valitse]
do
{

if((retval = select(highest_fd+1, &rfds, NULL, NULL, &tv)) == -1)  // retval on joka kerta 3
{
perror("select");
exit(EXIT_FAILURE);
}
else if(retval == 0)
{
printf("no descriptors ready\n");
}
else
{
printf("data available in %d file descriptor(s) \n", retval);

for(i = 0 ; i < N ; i++)
{
if((in = read(arr[i].fd[0], buf, sizeof(buf))) == -1) // tämä on surempi kuin 0 vain ensimmäisellä kerralla
{
perror("read");
exit(EXIT_FAILURE);
}
else if(in == 0)
{
printf("no data in buffer for fd %d \n", arr[i].fd[0]);
}
else
{
printf("reading from fd %d \n", arr[i].fd[0]);
printf("msg: %s \n", buf);
}
}
}

sleep(3);

}

Eli kun ohjelmassa päästä select() vaiheeseen
on kaikissa kolmessa putkessa dataa ja
ohjelma ilmoittaa, "data available in 3 file descriptor(s)"
ja tämän jälkeen lukee for -loopissa kaikista datan
ja printtaa sen ruudulle. Tämän jälkeen odotetaan
3 sekuntia ja palataan alkuun.

Toisella kierroksella ilmoitetaan jälleen, että
kolmessa putkessa on dataa ???, ja siirrytään
lukemaan dataa putkista. read() -funktio
ilmoittaa, kuten pitääkin, että dataa ei ole luettavissa.
Tämä jatkuu loputtomiin.

Miksi select() ilmoittaa joka kerta, että kolmessa
putkessa on dataa vaikka se on jo luettu sieltä?
Eikö read() -funktion tulisi tyhjentää puskuri
lukemisen jälkeen?

Toivottavasti joku C:tä paremmin osaava
osaa neuvoa. Kiitos.


satsuma

  • Käyttäjä
  • Viestejä: 63
    • Profiili
Re: select()
« Vastaus #1 : 28.07.06 - klo:09.30 »
Ahaa, katsoin uudestaan tuota select():n
man -sivua ja siellähän todetaankin, että
palautusarvo onkin kaikkien file descriptoreiden,
jotka on määritelty, summa.

Ok, tämä vähentää ymmärrystäni entisestään.
Eli kuinka tuota käytännössä käytetään?

_Pete_

  • Käyttäjä
  • Viestejä: 1836
  • Fufufuuffuuu
    • Profiili
Re: select()
« Vastaus #2 : 01.08.06 - klo:12.06 »
Aluksi kannataa asentaa manpages-dev jolloin voit man komennolla katsoa mitä on kerrottuna C-kirjastojen tarjoamista kutsuista:

sudo apt-get install manpages-dev

tämän jälkeen voit lukea select kutsusta komennolla:

man select

Tuolla olevasta esimerkki ohjelmasta lienee apua ?




satsuma

  • Käyttäjä
  • Viestejä: 63
    • Profiili
Re: select()
« Vastaus #3 : 01.08.06 - klo:12.21 »
Kiitos vastauksesta.


Tuolla olevasta esimerkki ohjelmasta lienee apua ?


Ei siitä oikein ole, se on vähän turhan yksinkertainen,
koska siinä luetaan vain yhtä file descriptoria (stdin) kerrallaan.

select_tut manuaali sivuilla on toinen esimerkki, mutta se
taas on niin sekava, etten oikein saa selvää mitä se tekee.

Jatkan yrittämistä.

_Pete_

  • Käyttäjä
  • Viestejä: 1836
  • Fufufuuffuuu
    • Profiili
Re: select()
« Vastaus #4 : 01.08.06 - klo:13.00 »

select_tut manuaali sivuilla on toinen esimerkki, mutta se
taas on niin sekava, etten oikein saa selvää mitä se tekee.

Jatkan yrittämistä.

Voisitko pistää koko ohjelmakoodisi näkyviin ...


satsuma

  • Käyttäjä
  • Viestejä: 63
    • Profiili
Re: select()
« Vastaus #5 : 01.08.06 - klo:13.19 »
Tässä on koodi, jolla olen yrittänyt saada select():n toimimaan.

Eli ohjelma toimii seuraavasti: Luodaan N(=3) kappaletta
lapsiprosesseja, joiden kanssa on luotu putki kommunikointia
varten. Alkuperäinen prosessi on "unessa" kunnes kaikki lapset
saavat kirjoitettua tietoa putkeen, jolloin alkuperäinen prosessi
käyttää select() funktiota selvittääkseen monessako putkessa
on dataa ja lukee kaikista, joissa on. Tämän jälkeen kutsutaan
uudestaan select() funktiota, joka ilmoittaa, että kaikissa on
dataa, mutta read() palauttaa nollan, eli dataa ei ole luettavissa.

Tuota viimeistä kohtaa en ymmärrä, eli miksi select() ilmoitta
kaikkien olevan valmiita, mutta read() ilmoittaa niiden olevan
tyhjiä?

Koodia: [Valitse]
#ifndef __stdio__
#include <stdio.h>
#define __stdio__
#endif

#ifndef __sys_types__
#include <sys/types.h>
#define __sys_types__
#endif

#ifndef __stdlib__
#include <stdlib.h>
#define __stdlib__
#endif

#ifndef __string__
#include <string.h>
#define __string__
#endif

#ifndef __sys_select
#include <sys/select.h>
#define __sys_select__
#endif


/*
struct_array.c
*/


#define N 3

struct proc
{
int pid;
int fd[2];
};

void child(int fd[], int time)
{
int out;
char msg[4];

close(fd[0]); // close read end

sleep(time+2);

if(time == 0)
strcpy(msg, "qui1");
else if(time == 1)
strcpy(msg, "qui2");
else
strcpy(msg, "qui3");

//if(time != 1)
//{
if((out = write(fd[1], msg, 4)) == -1)
{
// send message to parent that child is quitting
perror("write to pipe failed");
exit(EXIT_FAILURE);
}

printf("child %d: %d bytes written to pipe\n", time+1, out);
//}

}


int main(void)
{
int fd[2];
struct proc arr[N];
int i, j;
int pid;

char buf[4];

fd_set rfds; // fds for reading
struct timeval tv;
int retval;

int highest_fd = 0;

FD_ZERO(&rfds);

// timeout for select()
tv.tv_sec = 1; // seconds
tv.tv_usec = 0; // microseconds

for(i = 0 ; i < N ; i++)
{
if(pipe(fd) == -1)
{
perror("pipe failed");
exit(EXIT_FAILURE);
}

memcpy(arr[i].fd, fd, sizeof(fd));
printf("sizeof(fd): %d \n", sizeof(fd));

if((pid = fork()) == -1)
{
perror("fork failed");
exit(EXIT_FAILURE);
}
else if(pid == 0)
{
child(fd, i);
exit(EXIT_SUCCESS);
}

arr[i].pid = pid;

// determine higest fd
for(j = 0 ; j < 2 ; j++)
{
if(fd[j] >= highest_fd)
highest_fd = fd[j];
}

FD_SET(fd[0], &rfds);

close(fd[1]); // closes write end
}

for(i = 0 ; i < N ; i++)
{
printf("pid = %d, fd = %d, fd2 = %d \n", arr[i].pid, arr[i].fd[0], arr[i].fd[1]);
}

printf("highest_fd: %d \n", highest_fd);

sleep(7);

int in;
do
{

if((retval = select(highest_fd+1, &rfds, NULL, NULL, &tv)) == -1)
{
perror("select");
exit(EXIT_FAILURE);
}
else if(retval == 0)
{
printf("no descriptors ready\n");
}
else
{
printf("data available in %d file descriptor(s) \n", retval);

for(i = 0 ; i < N ; i++)
{

if(FD_ISSET(arr[i].fd[0], &rfds))
{
printf("descriptor %d is readable \n", arr[i].fd[0]);

if((in = read(arr[i].fd[0], buf, sizeof(buf))) == -1)
{
perror("read");
exit(EXIT_FAILURE);
}
else if(in == 0)
{
printf("no data in buffer for fd %d \n", arr[i].fd[0]);
}
else
{
printf("reading from fd %d \n", arr[i].fd[0]);
printf("msg: %s \n", buf);
}
}
}
}

sleep(3);

}
while(retval);


return 0;
}