Avatar billede netro Nybegynder
26. maj 2005 - 07:05 Der er 46 kommentarer og
1 løsning

Hvordan overfører man en instans til en tråd?

Jeg har en instans af en klasse, som jeg ønsker skal være tilgængelig i hver eneste tråd, der oprettes, men hvordan får jeg den ført med over til de nye tråde?

klasse k;

pthread_create (&se.sC_tr, NULL, serveClient,(void *) se.client_fd);

k skal altså overføres.
Avatar billede arne_v Ekspert
26. maj 2005 - 07:10 #1
du kan kun overføre en ting

men du kan vel lave en lille struct som indeholder både se.client_fd og en pointer til k ?

ellers kan du jo overveje at lave k klassen om til singleton
Avatar billede netro Nybegynder
26. maj 2005 - 07:26 #2
Okay, vil der være problemer ved at flere skriver til klasseinstansens variabler samtidig?
Avatar billede arne_v Ekspert
26. maj 2005 - 07:29 #3
det kan der godt

men:

pthread_mutex_init
pthread_mutex_lock
pthread_mutex_unlock
Avatar billede netro Nybegynder
26. maj 2005 - 07:37 #4
Kan du give et hurtigt eksempel på, hvordan jeg bedst opbygger structen, overfører den og aflæser dens variabler i serveClient()? Jeg er desuden i tvivl om, hvordan mutex bruges, så det må du også gerne uddybe, hvis du har tid.
Avatar billede arne_v Ekspert
26. maj 2005 - 08:12 #5
struct thread_info
{
    int fd;
    klasse K;
}

fyld værdi i, kalde med (void*)& og i thread funktionen caster du tilbage
til (thread_info*) og henter data ud
Avatar billede arne_v Ekspert
26. maj 2005 - 08:17 #6
setup:

pthread_mutex_t m;
pthread_mutexattr_t a;
pthread_mutexattr_init(&a);
pthread_mutex_init(&m,&a);

lock:

pthread_mutex_lock(&m);

unlock:

pthread_mutex_unlock(m);

husk at m skal være den samme m for alle tråde
Avatar billede netro Nybegynder
26. maj 2005 - 08:30 #7
Tak! Jeg får fejl, når jeg forsøget at caste tilbage.

(thread_info*) fd

invalid conversion from `thread_info*' to `int'
Avatar billede arne_v Ekspert
26. maj 2005 - 08:32 #8
du skal vel:

int fd = ((thread_info *)arg)->fd;
Avatar billede arne_v Ekspert
26. maj 2005 - 08:33 #9
og

klasse k = ((thread_info *)arg)->k;
Avatar billede netro Nybegynder
27. maj 2005 - 00:28 #10
Tak skal du have.

Der kommer ingen fejl, men der opstår et problem med flere klienter. Jeg gætter på, at det er file descriptoren, der får en forkert værdi.
Avatar billede arne_v Ekspert
27. maj 2005 - 07:17 #11
får du givet trådene hver sin fd ?
Avatar billede netro Nybegynder
27. maj 2005 - 14:55 #12
Det er i hvertfald planen selvfølgelig. Men jeg vil lige teste lidt mere i weekenden. Måske er det en åbenlys fejl.
Avatar billede netro Nybegynder
28. maj 2005 - 17:58 #13
Jeg har prøvet at udskrive file descriptoren i funktionen, der kaldes (thd er instansen af structen, der rummer fd-variablen):

void * serveClient (void * thd)
{
  cerr << ((thread_info*)thd)->new_fd;
}

Det virker fint, når den første klient forbinder sig, men når de næste klienter kommer på, udskrives new_fd ikke længere. Det ser ud som om, at klienterne på en eller anden måde får delt den samme file descriptor. For jeg kan nemlig lige få lov at skrive en enkelt kommando fra de næste klienter, inden de går ned, men resultatet bliver så vist hos den første klient, så vidt jeg kan se.
Avatar billede netro Nybegynder
28. maj 2005 - 18:00 #14
Og kaldet til at lave nye tråde ser sådan ud:

pthread_create (&se.sC_tr, NULL, serveClient, (void *) &thd);
Avatar billede arne_v Ekspert
28. maj 2005 - 18:02 #15
og thd bliver ikke overskrevet i den kaldende funktion ?
Avatar billede netro Nybegynder
28. maj 2005 - 18:08 #16
Det går jeg ikke ud fra, idet instansen er structen kun skulle blive erklæret én gang for alle og herefter overført til hver tråd, der skabes. Jeg skal skynde mig at sige, at jeg her ikke benytter mutex, da jeg ikke helt kunne gennemskue, hvordan det skulle laves. Så måske er det problemet?

struct threaddata
{
  ctrlstats cst;
  int new_fd;
};
   
-----------------------

server se;
ctrlsocket s;
thread_info thd;
s.socket();
s.bind();
s.listen();
while(1)
{
  thd.new_fd=s.myaccept();
  pthread_create (&se.sC_tr, NULL, serveClient, (void *) &thd);
}
Avatar billede netro Nybegynder
28. maj 2005 - 18:09 #17
threaddata hedder thread_info.
Avatar billede arne_v Ekspert
28. maj 2005 - 18:10 #18
den der kode overskriver da netop thd !
Avatar billede netro Nybegynder
28. maj 2005 - 18:11 #19
Aha.. Så har jeg nok ikke forstået det rigtigt?
Avatar billede arne_v Ekspert
28. maj 2005 - 18:15 #20
du har kun en thd, du smider adressen på den over til hver tråd, altså bruger
de alle samme thd
Avatar billede arne_v Ekspert
28. maj 2005 - 18:16 #21
server se;
ctrlsocket s;
thread_info *thd; // pointer
s.socket();
s.bind();
s.listen();
while(1)
{
  thd = new thread_info; // alloker
  thd->new_fd=s.myaccept(); // pointer derefence
  pthread_create (&se.sC_tr, NULL, serveClient, (void *) thd); // uden & da det er en pointer
}
Avatar billede netro Nybegynder
28. maj 2005 - 18:20 #22
Hele humlen er, at jeg gerne vil kende instansen "cst" i hver tråd, da disse skal kunne læse/skrive til/fra den samme variabel i klassen "ctrlstats".

Men jeg kan godt se nu, at file descriptoren overskrives i hver tråd, når jeg benytter samme instans. Hmm...
Avatar billede netro Nybegynder
28. maj 2005 - 18:22 #23
Jeg vil lige prøve dit forslag.
Avatar billede arne_v Ekspert
28. maj 2005 - 18:23 #24
struct threaddata
{
  ctrlstats *cst;
  int new_fd;
};

og lad cst for alle instanser pege på det samme
Avatar billede netro Nybegynder
28. maj 2005 - 18:48 #25
Okay, nu har jeg lavet "cst" til en pointer til "ctrlstats" og tilgår variablerne med: cst->variabel

Det kompilerer fint, men nu får jeg desværre en segmentation fault, når jeg starter første klient op.
Avatar billede netro Nybegynder
28. maj 2005 - 19:06 #26
Nu kan der i hvertfald godt komme flere klienter på. De får hver deres fd.

Men problemet med "cst" må jo være, at jeg ikke kan tilgå værdien af variablen i "ctrlstats" for den forrige tråd, når jeg opretter en ny instans med "thd = new thread_info;" for hver tråd.
Avatar billede arne_v Ekspert
28. maj 2005 - 19:08 #27
du skal jo:

thd->cst = &allescst;

inden du kalder
Avatar billede netro Nybegynder
28. maj 2005 - 19:27 #28
Hvad er allescst?

Det skal så stå lige inden pthread_create(...)?
Avatar billede netro Nybegynder
28. maj 2005 - 19:29 #29
Jeg forstår vist godt idéen i det, men kan ikke helt se det for mig.
Avatar billede arne_v Ekspert
28. maj 2005 - 19:39 #30
allecst er den cst som alle skal bruge (og hvor du skal bruge mutex til senere)

while(1)
{
  thd = new thread_info;
  thd->new_fd=s.myaccept();
  thd->cst = &allescst;
  pthread_create (&se.sC_tr, NULL, serveClient, (void *) thd);
}
Avatar billede netro Nybegynder
28. maj 2005 - 20:13 #31
Okay, hvordan erklærer jeg allescst og hvorhenne?
Avatar billede netro Nybegynder
28. maj 2005 - 20:15 #32
Ovenover while-løkken?

ctrlstats * allescst;
Avatar billede arne_v Ekspert
28. maj 2005 - 20:18 #33
det skal ikke være en pointer når vi bruger & på den
Avatar billede arne_v Ekspert
28. maj 2005 - 20:19 #34
og du må vel vide hvad det er for noget du skal have sendt over til trådene og
hvor i dit program du har de data
Avatar billede netro Nybegynder
28. maj 2005 - 20:44 #35
Det ved jeg skam også godt. Er bare i tvivl om metoden. Jeg prøver lige at lege lidt med det.
Avatar billede netro Nybegynder
28. maj 2005 - 23:51 #36
Hej Arne,

Det ser ud til at virke perfekt nu. Så jeg siger tak for din tålmodighed.

Har dog et mere generelt spørgsmål om server-clients. Hvis du har tid og lyst, kan du få nogle flere points. Under alle omstændigheder må du gerne lægge et svar.
Avatar billede arne_v Ekspert
28. maj 2005 - 23:53 #37
ok
Avatar billede arne_v Ekspert
28. maj 2005 - 23:55 #38
og bare spørg løs

men det bliver måske først imorgen at jeg svarer - klokken er mange
Avatar billede netro Nybegynder
29. maj 2005 - 02:53 #39
Tak. Jeg laver en simpel stastistik over antal klienter, der er tilsluttet. Det er bl.a. det, som jeg bruger klassen "ctrlstats" til. Jeg tæller én op lige efter accept()-kaldet, og det går fint. Men jeg kan ikke få talt ned, når en klient afbryder forbindelsen (fx ved at lukke prompt-vinduet).

I "void * serveClient (void * thd)" har jeg en uendelig løkke, hvori der kaldes en receive-funktion, som modtager data fra klienten. Mit bedste bud var at fratrække antallet én lige efter denne løkke, men det fungerer ikke. Desuden lukkes serveren ned, hvis en klient lukkes, og det er jo ikke ligefrem smart.

Kan du sige noget generelt om, hvad der er smartest at gøre hvor?
Avatar billede netro Nybegynder
29. maj 2005 - 03:00 #40
Sig til hvis du vil se noget mere kode. Jeg ville bare ikke begynde at paste en masse ind, hvis du ikke har brug for det.
Avatar billede netro Nybegynder
29. maj 2005 - 19:33 #41
Jeg har også prøvet med en pthread_exit nederst i void * serveClient (void * thd) - men det spiller ikke desværre.
Avatar billede arne_v Ekspert
29. maj 2005 - 20:11 #42
din per client tråd skal catche når den får een fejl på socketen og selv tælle
counteren ned inden den dør
Avatar billede netro Nybegynder
29. maj 2005 - 20:42 #43
Det må jeg vist lige tænke lidt over.

Mht. at serveren går ned, når en klient afbryder. Kan du sige, hvad det kan skyldes, uden at have set alt koden?
Avatar billede arne_v Ekspert
29. maj 2005 - 21:26 #44
svært at sige

tester du på returværdi af recv ?
Avatar billede netro Nybegynder
29. maj 2005 - 21:35 #45
Jeg har fundet frem til, at der bliver sendt en tom pakke til serveren, når den først tilsluttede klient afbryder forbindelsen.
Avatar billede arne_v Ekspert
29. maj 2005 - 23:04 #46
når recv returnerer 0 betyder det ikke at der er sendt en pakke med 0 bytes, men at
connection er gone
Avatar billede netro Nybegynder
30. maj 2005 - 11:45 #47
Ja, jeg har lavet et tjek på recv, og det løser begge problemer.

Mange tak for hjælpen.
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester