27. oktober 2002 - 17:04Der er
13 kommentarer og 1 løsning
Globale variable ved fork
Jeg har et standard c-program i linux der arbejder på nogle globale variable. Det fungerer som en server, der forker hver gang det modtager en forespørgsel. Mit problem er nu, at når childprocesserne ændrer de globale variable, ændres de ikke i parentprocessen.
Hvordan får jeg gjort det sådan at de globale variable kun oprettes en gang, og ikke kopieres med i childprocesserne. Det jeg søger er altså noget lignende kommandoen "static" i java...
Hvis du laver en fork() i C, så kopierer du hele konteksten til et nyt adresserum. Ved brug af letvægtsprocesser (aka. threads/tråde) ligger de i samme adresserum - de er en del af samme proces. Bl.a. herfor er tråde billige at oprette i forhold til processer.
Hvis du vil lave "globale variabler" for adskilte processer skal de enten ligge i shared memory (som er et systemkald), eller osse skal du lave noget f.eks. som at oprette to pipes (én læse- og én skrive-) *inden* du laver en fork(). Derefter kan du give forældreprocessen besked om at du vil ændre en global variabel.
Du kan godt bruge message passing - det er derfor, der står "F.eks."...
Hvis du angiver childprocesserne til at arbejde i samme adresserum som forældreprocessen, så har du problemer: Hvordan sikrer du, at dine processer kun deler globale variabler, og ikke bruger den enes program segment som temporært lager for den anden? Ved fork() er det pr. definition en kopi af dit program, der udføres i et andet adresserum. Det vil simpelthen give dig muchomange problemer hvis du kunne få to processer til at køre i samme adresserum. Hvis du virkelig ønsker det, kan du så ikke bruge threads i stedet?
Du kan ikke sende argumenter med i et kald til fork().
Hvis du vil give childprocessen noget at arbejde med, kan du lægge nogle værdier i variabler inden kaldet til fork(), og det første din nye proces skal gøre er at læse disse (kopierede) variabler og udføre noget i overensstemmeler hermed.
Men du kan også sende noget i en pipe/queue/shared memory. Du kan jo sende hvad som helst - og det er så op til modtageren at fortolke det modtagne på passende vis. Hvis det drejer sig om en pointer til noget shared memory, så kan du endda bruge den til noget, men hvis det er til forældreprocessens eget adresserum, vil du få en over de virtuelle fingre (dvs. ethvert operativsystem opbygget efter moderne flerproces- og flerbrugerprincipper vil gøre det).
Der findes en beslægtet version af fork(), der hedder vfork(). Den er udelukkende beregnet til at lave en proces, der enten kalder exec() (starte et andet, eksternt program) eller exit() (afslutte sin proces). Da dette sker ret hurtigt, og da processen ikke skal køre noget programkode selv, får denne childproces lov til at køre i samme adresserum. Det er imidlertid sindssygt farligt at bruge den til andet end dette, da der ikke er nogen beskyttelse på adresserummet...
Nu ved jeg ikke, hvorfor du helst vil undgå shared memory, men det er den hurtigste form for inter-proceskommunikation, der er på maskinen. Det er let at bruge, men har en begrænsning i størrelsen af den delte område (systembestemt). Eneste lille finte er at man skal huske at afskærme ressourcerne ved brug af semaforer, fillåse eller lignende.
Kom lige til at tænke på: Gu' ved om man kan lave følgende (i pseudokode):
opret shared memory opret to pipes fra og til sig selv: én læsepipe og én skrivepipe skriv værdier til pipe pid = fork() hvis pid = 0 /* vi er i child-processen */ læs fra pipe ellers /* vi er i forældreprocessen */ gør noget andet
Jeg ved ikke om det kan lade sig gøre, og resultatet er vel ikke anderledes end hvis forældreprocessen *efter* et kald til fork() skriver til sit nye barn gennem en pipe?
Jeg havde ellers regnet med at alle mine childprocesser kunne "pege" dvs. pointers ind mod den samme liste... uden shared memory men det lader til at det ikke kan lade sig gøre det kunne ellers være smart!
Okay, jeg er blevet overbevist om at bruge shared memory. Problemet er bare, at det er en hægtet liste jeg arbejder med, hvordan får jeg lagt den ind i shared memory? Jeg kan godt få lagt et element fra listen ind i shared memory, men hvordan lægger jeg hele listen ind? Skal jeg oprette et shared memory-segment for hvert listeelement?, og hvordan får jeg så segmenterne til at pege på hinanden?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.