Avatar billede conrad Nybegynder
31. oktober 2003 - 20:17 Der er 16 kommentarer og
1 løsning

Tråde i c++ på Linux

Da jeg er ved at implementere en protokol har jeg brug for at kunne 
monitorere en tabel med ACKS med jævne mellemrum. Lige nu scanner jeg tabellen for udløbne ACKs hvergang jeg indsætter en nu.

Det ideelle ville være at køre en tråd som gjorde dette.

Jeg har kigget på pthreads (har også engang brugt dem på Minix), men synes ikke jeg kan finde et C++ eksempel hvor en klasse opretter en tråd og også indeholder den metode tråden skal køre.

Er der nogen der har et ultra simpelt eksempel eller et alternativ?
(fork()tvivler jeg selv på)
Avatar billede arne_v Ekspert
31. oktober 2003 - 20:30 #1
pthread_create's 3. argument skulle gerne være en funktion der kan køres.

(pthreads er C orienteret ikke C++ orienteret - derfor funktion ikke metode)

Men på Unix er man traditionelt mere til fork end til threads.
Avatar billede bertelbrander Novice
31. oktober 2003 - 20:59 #2
Hvis du kun har en instans af klassen, kan du bruge en static member funtion (ThreadEntry) der kalder en normal member function (RealThreadEntry):

class MyThreadClass
{
public:
  MyThreadClass()
  { 
    me = this;
  }
  void RealThreadEntry();
  static void ThreadEntry(void)
  {
    me->RealThreadEntry();
  }
  static MyThreadClass *me;
};

Og så bruger du MyThreadClass::ThreadEntry, som den function der skal angives som den 3. argument til pthread_create.
Avatar billede bertelbrander Novice
31. oktober 2003 - 21:04 #3
Så lige at functionen som man angiver til pthread_create tager en void * som argument (på cygwin), så kan man også lave:

class MyThreadClass
{
public:
  void RealThreadEntry();
  static void ThreadEntry(void *me)
  {
    me->RealThreadEntry();
  }
};

MyThreadClass MyThread:
pthread_create(..., ..., MyThread::ThreadEntry, &MyThread)
Avatar billede conrad Nybegynder
31. oktober 2003 - 21:28 #4
Bertel>>Jeg har flere en et objekt

Med fork() får jeg en ny proces som er en kopi af den gamle, det vil vel sige at jeg får 2
forskellige tabeller med ACKs at holde styr på, og skal lave en eller anden form for kommunikation imellem de 2 (vha pipes?). Er det korrekt?
Avatar billede arne_v Ekspert
31. oktober 2003 - 22:04 #5
Er det ikke aller nemmest at kalde pthread_create med:
  en god gammeldags "C style" funktion
  sit objekt
og så lade funktionen kalde den rigtige metode på objektet ?
Avatar billede arne_v Ekspert
31. oktober 2003 - 22:05 #6
Jeg har aldrig programmeret med fork selv, men de fleste Unix programmer
bruger fork, så jeg formoder at det er brugbart.
Avatar billede conrad Nybegynder
31. oktober 2003 - 22:46 #7
Jeg tror faktisk at følgende virker efter hensigten:

#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;

class Object
{
public:
  void start()
  {
    pthread_t id1, id2;
    data = 0;
    cout << "data = " << data << endl;
    pthread_create(&id1, NULL, func1, this);
    sleep(1);
    cout << "data = " << data << endl;
    pthread_create(&id2, NULL, func2, this);
    sleep(1);
    cout << "data = " << data << endl;
  }

  static void *func1(void *param)
  {
    Object *obj = reinterpret_cast<Object *>(param);
    obj->data = 52;
  }

  static void *func2(void *param)
  {
    Object *obj = reinterpret_cast<Object *>(param);
    obj->data = 12;
  }

  int data;
};

int main()
{
  Object myobject;
  myobject.start();
  return 0;
}
Kan ikke helt gennemskue om det var det Bertel mente. Og om det er en OK måde at stoppe trådene på?
Avatar billede conrad Nybegynder
31. oktober 2003 - 22:48 #8
Grrrr, det var forkert pastet (ovenstående var det jeg byggede videre på)

#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;

class Object
{
public:
    Object(int i)
    {
      this->data = i;
        this->go = true;
    }
   
  void start()
  {
    pthread_t id1;
    cout << "data = " << data << endl;
    pthread_create(&id1, NULL, func1, this);
    sleep(1);
    }

    void stop()
    {
      this->go = false;
    }

    int getData()
    {
        return this->data;
    }   
   
  static void *func1(void *param)
  {
    Object *obj = reinterpret_cast<Object *>(param);
    while(obj->go)
        {
            obj->data = obj->data+1 ;
            cout << "Thread Working\n" << ' ';
            sleep(10);
        }
        return 0;//for some reason the compiler requires we return something??
    }

    int data;
    bool go;
};

int main()
{
  Object myobject1(1);
    Object myobject2(100);
    cout << myobject1.getData() << endl;
    cout << myobject2.getData() << endl;
    myobject1.start();
    myobject2.start();
    for(int i = 0; i < 30; i++)
    {
      cout << "Working:"<<i << endl;
        sleep(1);
    }
    myobject1.stop();
    myobject2.stop();
    cout << myobject1.getData() << endl;
    cout << myobject2.getData() << endl;

return 0;
}

Kan bare ikke helt gennemskue om det var det Bertel mente. Og om det er en OK måde at stoppe trådene på?
Avatar billede arne_v Ekspert
31. oktober 2003 - 22:49 #9
sleep(1) er nok ikke optimalt.

Brug pthread_join og pthread_detach !
Avatar billede conrad Nybegynder
31. oktober 2003 - 23:06 #10
static void *func1(void *param)
  {
    Object *obj = reinterpret_cast<Object *>(param);
    while(obj->go)
        {
            obj->data = obj->data+1 ;
            cout << "Thread Working\n" << ' ';
            sleep(10);
        }
        return 0;//for some reason the compiler requires we return something??
    }

    int data;
    bool go;
};

int main()
{
  Object myobject1(1);
    Object myobject2(100);
    cout << myobject1.getData() << endl;
    cout << myobject2.getData() << endl;
    myobject1.start();
    myobject2.start();
    for(int i = 0; i < 30; i++)
    {
      cout << "Working:"<<i << endl;
        sleep(1);
    }
    myobject1.stop();
    myobject2.stop();
    cout << myobject1.getData() << endl;
    cout << myobject2.getData() << endl;

return 0;
}

Kan bare ikke helt gennemskue om det var det Bertel mente. Og om det er en OK måde at stoppe trådene på?
Avatar billede arne_v Ekspert
31. oktober 2003 - 23:09 #11
Jeg har allerede foreslået pthread_join og pthread_detach !
Avatar billede arne_v Ekspert
31. oktober 2003 - 23:10 #12
return 0;

er nødvendig fordi du har:

static void *func1(void *param)

d.v.s ikke en function returnerer ingenting men en funktion som returnerer
en pointer til et eller andet.
Avatar billede conrad Nybegynder
31. oktober 2003 - 23:12 #13
Undskyld - den her Mozilla gemmer det man skriver her efter man har postet det -

grunden til jeg brugte sleep(1) var bare for at "simulere" at main tråden lavede noget.
Jeg tror ikke join vil være det rigtige for tråden skal bare blive ved at køre og monitorere ACK tabellen. Mon ikke snarere jeg skal indsætte pthread_exit()

i bunden af func1(). Det vil vel lukke den kaldende tråd?
Avatar billede arne_v Ekspert
31. oktober 2003 - 23:15 #14
Jep.
Avatar billede conrad Nybegynder
31. oktober 2003 - 23:21 #15
Lækkert jeg tror faktisk det virker nu (mangler lige at synkronisere tabellen men det er en anden snak). Tak for hjælpen begge 2! Og så må i gerne svare (eller er der noget med Bertel ikke vil have point?)
Avatar billede arne_v Ekspert
31. oktober 2003 - 23:23 #16
svar
Avatar billede bertelbrander Novice
31. oktober 2003 - 23:48 #17
Som du har lavet det, er func1 en static funktion, dvs. den kan ikke tilgå ikke-static objekter (funktioner og variable) i sin klasse. Derfor er du nød til at bruge obj-> til at få fat i disse.

Det jeg var ude på var at få din thread funktion til at være en ikke-static funktion. Det kan du opnå ved at kalde en ikke-static funktion gennem obj-> i func1.

Jeg forsøger stadig at undgå point.
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