/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
fork() og copy-constructors
Fra : Stephan Henningsen


Dato : 19-05-01 00:23

Hej,

Jeg er godt igang med en tcpserver-klasse. Den kører fint,
og jeg har også vha. noget afskrivning og fusk fået fork()
til at lave en ny tråd, når der kommet en ny process.

Men jeg synes ikke, at mit server-objekts statiske tæller,
som holder øje med, hvor mange servere, der er instantieret,
tæller op, når fork() starter en ny. Jeg tænkte på, om det
måske kunne have noget at gøre med, at fork() kopiere al
data *råt* uden kald til klassens cctors?

Socket-kaldet listen(int port, int backlog) tager to
parametre, hvoraf den sidste, skulle angive, hvormange
forbindelser, der er tillandt at have ventende, inden
klienten for opkoblingsfejl (ikke sandt?). Men efter en
fork() er det atter som om, at der sker noget, med en
tæller, og backlog har ingen effekt...

Jeg har lagt min kode herud:

http://212.10.213.249/~stephan/tcpsocket/

hvor server.cpp nok er den mest interessant.

Håber nogen kunne hjælpe og evt. kommentere koden; det er
første gang jeg kaster mig ud i exception-handling. Jeg
synes det ser noget sært ud. Måske skulle jeg bare holde
mig til at kaste et generelt tcperr-objekt ved fejl, i
stedet for en til hver klasse (tcpbase, tcpserver,
tcpclient..).

--
Stephan Henningsen /
/ http://tisprut.dk


 
 
Kent Friis (19-05-2001)
Kommentar
Fra : Kent Friis


Dato : 19-05-01 08:21

Den Sat, 19 May 2001 01:22:57 +0200 skrev Stephan Henningsen:
>Hej,
>
>Jeg er godt igang med en tcpserver-klasse. Den kører fint,
>og jeg har også vha. noget afskrivning og fusk fået fork()
>til at lave en ny tråd, når der kommet en ny process.
>
>Men jeg synes ikke, at mit server-objekts statiske tæller,
>som holder øje med, hvor mange servere, der er instantieret,
>tæller op, når fork() starter en ny. Jeg tænkte på, om det
>måske kunne have noget at gøre med, at fork() kopiere al
>data *råt* uden kald til klassens cctors?

fork() kalder ikke nogen constructors. fork() er et systemkald, og
derfor ligeglad med om du kører C, C++, lisp, pascal,...

Det er altså bare alle data der bliver kopieret råt. (Eller for fx.
linux' vedkommende, ser det bare sådan ud (shared, copy on write)).

Mvh
Kent
--
http://www.celebrityshine.com/~kfr/ - nu med Elgo-billeder

Anders Bo Rasmussen (19-05-2001)
Kommentar
Fra : Anders Bo Rasmussen


Dato : 19-05-01 08:42

On Sat, 19 May 2001 01:22:57 +0200,
Stephan Henningsen <stephan@levelout.tisprut.dk> wrote:

>Men jeg synes ikke, at mit server-objekts statiske tæller,
>som holder øje med, hvor mange servere, der er instantieret,
>tæller op, når fork() starter en ny. Jeg tænkte på, om det
>måske kunne have noget at gøre med, at fork() kopiere al
>data *råt* uden kald til klassens cctors?

Fra man fork, på en Linuxkasse:

Under Linux, fork is implemented using copy-on-write
pages, so the only penalty incurred by fork is the time
and memory required to duplicate the parent's page tables,
and to create a unique task structure for the child.

Så på en Linux-kasse bliver copyconstructorene ikke kaldt, men dataene
bliver kopieret "råt", hvis/når det er nødvendigt.

Fra W. Richard Stevens, Unix Networking Programming, Interprocess
Communications:

Memory is copied from the parrent to the child, all discriptors are
duplicated in the child, and so on. Current implementations use a
technique called copy-on-write, which avoids a copy of the parent's data
space to the child until the child needs its own copy; but regardless of
this optimization fork is expensive.


Jeg har ikke læst din kode, men regner med at du har problemer med, at
du ikke regner med at lageret bare bliver kopieret ved fork.

--
Anders Bo Rasmussen mailto:fuzz01@spamfilter.dk
Frimestervej 42 1.tv http://www.fuzz.dk
2400 Kbh. NV
Denmark

Igor V. Rafienko (19-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 19-05-01 17:54

* Stephan Henningsen

> Jeg er godt igang med en tcpserver-klasse. Den kører fint, og jeg
> har også vha. noget afskrivning og fusk fået fork() til at lave en
> ny tråd, når der kommet en ny process.


Rent teknisk lager ikke fork() en tråd, men en ny prosess, men sin
egen memory. Det er fremdeles mulig å få flere prosesser (som stammer
fra samme forelder) til å ha adgang til felles hukommelse, men jeg så
ikke antydninger til noe slikt i koden.

Apropos servere, fork() og tcp: W.R. Stevens i UNPv1 skrev et helt
kapittel der han sammenlignet forskjellige måter å lage en
nettverksserver på. Det kan være verdt å ta en titt på.


> Men jeg synes ikke, at mit server-objekts statiske tæller,


int tcpserver :: servers?


> som holder øje med, hvor mange servere, der er instantieret, tæller
> op, når fork() starter en ny. Jeg tænkte på, om det måske kunne have
> noget at gøre med, at fork() kopiere al data *råt* uden kald til
> klassens cctors?


Mnja, muligens, men hvordan regnet du at ting skulle fungere?

Så vidt jeg kan se fra koden din (server.cpp), har du instansiert 1
server (tcpserver) som venter på oppkoblinger. Når det kommer en slik,
en, kaller du fork() og sender data i barneprosessen.

Selv om klassector'en skulle ha blitt kalt, ville ikke det hatt noe
virkning, da du ville ha fått 2 prosesser med hver sin egen kopi av
tellevariabelen.

Hvis du vil telle antall barneprosesser, blir det en relativt grei sak
dersom du teller opp slike for hver gang fork() lykkes, og teller de
ned, når du får SIGCHLD og greier å wait'e (beklager språkbruken) på
barneprosessene. Stevens sin APUE er igjen meget hjelpsom på dette
punktet.


> Socket-kaldet listen(int port, int backlog) tager to parametre,
> hvoraf den sidste, skulle angive, hvormange forbindelser, der er
> tillandt at have ventende, inden klienten for opkoblingsfejl (ikke
> sandt?).


Mnja, ikke helt:

The backlog parameter defines the maximum length the queue
of pending connections may grow to.

If a connection request arrives with the queue full, the
client will receive an error with an indication of ECONNRE-
FUSED for AF_UNIX sockets. If the underlying protocol sup-
ports retransmission,
the connection request may be ignored so that retries may
succeed. For AF_INET sockets, the tcp will retry the connec-
tion. If the backlog is not cleared by the time the tcp
times out, the connect will fail with ETIMEDOUT.

iirc angir backlog hvor mange forbindelser en server får ha utestående
i tilstanden SYN_RCVD (rfc 793 -- TCP spec'en. Eller ta en titt i
Stevens); dvs. hvor mange oppkoblinsforespørsler er "registert" men
ikke opprettet enda.


> Men efter en fork() er det atter som om, at der sker noget, med en
> tæller, og backlog har ingen effekt...


Hva slags effekt var du ute etter?

[snip]





ivr
APUE == Advanced Programming In The UNIX Environment
UNPv1 == UNIX Network Programming, Volume I: sockets and XTI
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Stephan Henningsen (20-05-2001)
Kommentar
Fra : Stephan Henningsen


Dato : 20-05-01 23:54

On 19 May 2001 18:54:15 +0200, Igor V. Rafienko wrote:
>
>Apropos servere, fork() og tcp: W.R. Stevens i UNPv1 skrev et helt
>kapittel der han sammenlignet forskjellige måter å lage en
>nettverksserver på. Det kan være verdt å ta en titt på.

Det er bare en skam, at alle de bøger koster så f*ndens
meget! Jeg ville meget hellere have noget materiale her på
nettet, hvis du kender til noget?


>> Men jeg synes ikke, at mit server-objekts statiske tæller,
>
>int tcpserver :: servers?

Præcist.


>> Men efter en fork() er det atter som om, at der sker noget, med en
>> tæller, og backlog har ingen effekt...
>
>Hva slags effekt var du ute etter?

Jeg ville ganske enkelt have oprettet et nyt server-objekt
til hver eneste forbindelse ud. Men det må ikke være
rå-kopier, ligesom fork() laver dem, fordi
int tcpserver::servers skal tælles op. Jeg ved heller ikke,
om dette er den smarteste måde at implementere en
objektorienteret server-løsning på, men det var blot min
første tanke, og jeg troede at fork() kunne hjælpe mig til
dette.

Angående backlog, så troede jeg, at det var antallet af
forbindelser, der ville blive modtaget på den pågældende
socket. Jeg prøvede at sætte den til 1 og telnette til den
X antal gange samtidigt, i håb om, at klienterne ville få
nægtet adgang; men i stedet resulterede det i en X-server
der gik ned med et brag! =)


--
Stephan Henningsen /
/ http://tisprut.dk


Igor V. Rafienko (21-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 21-05-01 18:02

* Stephan Henningsen

[snip]

> Det er bare en skam, at alle de bøger koster så f*ndens
> meget!


Da får du begynne å spare :)


> Jeg ville meget hellere have noget materiale her på nettet, hvis du
> kender til noget?


nope.

[snip]


> > Hva slags effekt var du ute etter?
>
> Jeg ville ganske enkelt have oprettet et nyt server-objekt til hver
> eneste forbindelse ud. Men det må ikke være rå-kopier, ligesom
> fork() laver dem, fordi int tcpserver::servers skal tælles op.


Tell antall servere før fork() og fang opp SIGCHLD for å telle ned
servere. Evt. kan man dille med en eller annen form for kommunikasjon
(fx. pipes) mellom prosessene.

[snip]


> Angående backlog, så troede jeg, at det var antallet af
> forbindelser, der ville blive modtaget på den pågældende socket.


Åh nei, backlog er definitivt noe annet.





ivr
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Stephan Henningsen (21-05-2001)
Kommentar
Fra : Stephan Henningsen


Dato : 21-05-01 22:05

On 21 May 2001 19:02:25 +0200, Igor V. Rafienko wrote:
>* Stephan Henningsen
>
>[snip]
>
>> Det er bare en skam, at alle de bøger koster så f*ndens
>> meget!
>
>
>Da får du begynne å spare :)

Godt det er snart jul, så kan bøgerne komme på ønskelisten =).


>> Jeg ville ganske enkelt have oprettet et nyt server-objekt til hver
>> eneste forbindelse ud. Men det må ikke være rå-kopier, ligesom
>> fork() laver dem, fordi int tcpserver::servers skal tælles op.
>
>Tell antall servere før fork() og fang opp SIGCHLD for å telle ned
>servere. Evt. kan man dille med en eller annen form for kommunikasjon
>(fx. pipes) mellom prosessene.

Det kan jeg ikke lige overskue, hvordan skulle gøres i
objekter. Jeg kunne godt kalde server->increment() før
fork(), og server->decrement() unden child-processen
kalder exit(0), men det virker noget fusket. Jeg havde
gerne set, at constructoren havde gjort det på
"C++-metoden".

Vil pthreads være bedre, eller gør de i bund og grund det
samme som fork(), altså taget en rå kopi?


--
Stephan Henningsen /
/ http://tisprut.dk


Igor V. Rafienko (22-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 22-05-01 10:11

* Stephan Henningsen

[snip]

> >Da får du begynne å spare :)
>
> Godt det er snart jul, så kan bøgerne komme på ønskelisten =).


Alle spøk til side: gode bøker pleier å koste en mengde penger, noe
jeg synes virker ganske rimelig: tenk hvor lang tid Stevens må ha
brukt på å skaffe seg den kompetansen (og de skriveferdighetene) som
muliggjorde UNPv1-2 og TCPv1-3.

Dette er liksom ikke helt "teach yourself home computer in 21 minutes"
eller "BeeJay's networking guide" :)

[snip]


> > Tell antall servere før fork() og fang opp SIGCHLD for å telle ned
> > servere. Evt. kan man dille med en eller annen form for
> > kommunikasjon (fx. pipes) mellom prosessene.
>
> Det kan jeg ikke lige overskue, hvordan skulle gøres i objekter. Jeg
> kunne godt kalde server->increment() før fork(),


Lag en metode i server-klassen (egentlig er det et utrolig dårlig
navn) som heter "process_request" elns. Denne vil kalle fork() selv. I
denne metoden kan du inkrementere så mange tellere som du vil. Når det
gjelder det å telle barn som er avsluttet, er det litt mer vanskelig
(det er ganske ekkelt å binde en signal-handler til en
medlemsfunksjon), men fremdeles mulig å jobbe seg rundt.

Ad det med dårlige navn (nå kommer SocketServer reklamen fra python):

Jeg ville ha lagt en "listener" klasse som tok imot oppkoblinger på en
bestemt port (eller en rekke porter). Etter at man oppdager at det
kommer en ny forbindelse, kan man fork()'e og:

1) i forelderprosessen (listener klassen) økes telleren (som dertil
ikke trenger å være statisk)

2) i barneprosessen instansieres "server" klassen som skal behandle
forespørselen.

Ta en titt på hvordan SocketServer fungerer i Python.

Denne skillen mellom listener og server vil også tillate å lage en
threaded (såvel som single-threaded) server veldig enkelt (i Python
har man mixin-klasser til dette formålet, men ting kan fikses i C++ på
en tilsvarende måte).

Det at koden er OO er neppe et mål i seg selv. Løsningen skissert over
blir ganske pen.


> og server->decrement() unden child-processen kalder exit(0),


Ehh, du vil aldri greie å dekrementere en variabel i en annen prossess
uten videre magi (som fx. signals (og da er SIGCHLD en like grei
måte), pipes, shared memory eller tilsvarende ekkelskap).

[snip]


> Vil pthreads være bedre, eller gør de i bund og grund det samme som
> fork(), altså taget en rå kopi?


Den opplagte fordelen er at alt sammen er i en prosess.





ivr
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Stephan Henningsen (22-05-2001)
Kommentar
Fra : Stephan Henningsen


Dato : 22-05-01 21:23

On 22 May 2001 11:10:53 +0200, Igor V. Rafienko wrote:
>Alle spøk til side: gode bøker pleier å koste en mengde penger, noe
>jeg synes virker ganske rimelig: tenk hvor lang tid Stevens må ha
>brukt på å skaffe seg den kompetansen (og de skriveferdighetene) som
>muliggjorde UNPv1-2 og TCPv1-3.
>
>Dette er liksom ikke helt "teach yourself home computer in 21 minutes"
>eller "BeeJay's networking guide" :)

Rigtigt. Jeg har ikke læst nogen af de bøger, du omtaler,
men BeeJay's er god, fordi man nemt og hurtigt for banket
noget kode samme, der virker (jaja, der er sikkert situationer,
hvor koden er fejlbehæftet) -- lige det, jeg har brug for =).


>Jeg ville ha lagt en "listener" klasse som tok imot oppkoblinger på en
>bestemt port (eller en rekke porter). Etter at man oppdager at det
>kommer en ny forbindelse, kan man fork()'e og:
>
>1) i forelderprosessen (listener klassen) økes telleren (som dertil
>ikke trenger å være statisk)
>
>2) i barneprosessen instansieres "server" klassen som skal behandle
>forespørselen.

Men så kører alting jo inde i server-objektet, uden for
rækkevidde af det program, der anvender server-objektet.
Det er ikke meningen.

Jeg vil jo bare lave en simpel og alsidig server- og
klient-klasse, som kan henholdsvis lytte+sende+modtage og
sende+modtage. På den måde skulle det senere være forholdsvis
nemt at lave en hvilken som helst server og klient, ved brug
af disse klasser.

Jeg har en tcpbase::listen_for_connection, og denne nedarves
kun til tcpserver-klassen; ikke tcpclient.


>> og server->decrement() unden child-processen kalder exit(0),
>
>Ehh, du vil aldri greie å dekrementere en variabel i en annen prossess
>uten videre magi (som fx. signals (og da er SIGCHLD en like grei
>måte), pipes, shared memory eller tilsvarende ekkelskap).

Nånej.. Objektet i barn-processen ( =) ) inkrementeres
ganske vist, men slettes når processen dør.


>> Vil pthreads være bedre, eller gør de i bund og grund det samme som
>> fork(), altså taget en rå kopi?
>
>Den opplagte fordelen er at alt sammen er i en prosess.

Så det er vist løsningen på mit problem. Jeg vil kigge lidt
på pthreads...


--
Stephan Henningsen /
/ http://tisprut.dk


Igor V. Rafienko (23-05-2001)
Kommentar
Fra : Igor V. Rafienko


Dato : 23-05-01 22:09

* Stephan Henningsen

> Rigtigt. Jeg har ikke læst nogen af de bøger, du omtaler,
> men BeeJay's er god, fordi man nemt og hurtigt for banket
> noget kode samme, der virker (jaja, der er sikkert situationer,
> hvor koden er fejlbehæftet) -- lige det, jeg har brug for =).


<URL:http://www.norvig.com/21-days.html>


> >Jeg ville ha lagt en "listener" klasse som tok imot oppkoblinger på en
> >bestemt port (eller en rekke porter). Etter at man oppdager at det
> >kommer en ny forbindelse, kan man fork()'e og:
> >
> >1) i forelderprosessen (listener klassen) økes telleren (som dertil
> >ikke trenger å være statisk)
> >
> >2) i barneprosessen instansieres "server" klassen som skal behandle
> >forespørselen.
>
> Men så kører alting jo inde i server-objektet, uden for rækkevidde
> af det program, der anvender server-objektet. Det er ikke meningen.


Nei, server-"prosessen" blir egen klasse:

#include "server.h"


class listener
{
public:
void process_connection( int sock )
{
   if ( pid_t child = fork() ) {
    in_progress.push_back( child );
    return ;
   }
   
   // child process
   close( listen_sock );
   server *s = new server( sock );
   server.doIt();
   exit( 0 );
}
}   


> >Ehh, du vil aldri greie å dekrementere en variabel i en annen
> >prossess uten videre magi (som fx. signals (og da er SIGCHLD en
> >like grei måte), pipes, shared memory eller tilsvarende ekkelskap).
>
> Nånej.. Objektet i barn-processen ( =) ) inkrementeres
> ganske vist,


det hjelper da særs lite, hva?

[snip]





ivr
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing.
                  -- Dick Brandon

Jesper Gødvad (27-05-2001)
Kommentar
Fra : Jesper Gødvad


Dato : 27-05-01 22:48


> Vil pthreads være bedre, eller gør de i bund og grund det
> samme som fork(), altså taget en rå kopi?

Hvis du vil bruge fork( ) skal du kigge på semaforer til at tælle dine
processer.

Jeg har brugt pthreads i min løsning. Det fungerer godt i praksis, men
teoretisk vil det give performance problemer.

Her er desuden et par links du måske vil finde nyttige:

http://linas.org/linux/threads-faq.html#ThreadsDefinition

http://users.actcom.co.il/~choo/lupg/tutorials/multi-thread/multi-thread.htm
l

mvh. jesper



John Mørck Hansen (21-05-2001)
Kommentar
Fra : John Mørck Hansen


Dato : 21-05-01 08:39

"Stephan Henningsen" <stephan@levelout.tisprut.dk> skrev
>
> Men jeg synes ikke, at mit server-objekts statiske tæller,
> som holder øje med, hvor mange servere, der er instantieret,
> tæller op, når fork() starter en ny. Jeg tænkte på, om det
> måske kunne have noget at gøre med, at fork() kopiere al
> data *råt* uden kald til klassens cctors?

Ja, det har det!

Hvis du vil havde adgang til variabler mellem hovedprocessen og
underprocesserne så vil jeg mene du skal bruge fælles-hukommelse (share
memory) i dit program.

Jeg er ikke super unix/linux programør men det er da hvad jeg har kunne læse
mig til !!!


(John =



Søg
Reklame
Statistik
Spørgsmål : 177501
Tips : 31968
Nyheder : 719565
Indlæg : 6408522
Brugere : 218887

Månedens bedste
Årets bedste
Sidste års bedste