# C++ Adressen übergeben



## Jens Hibbeler (15. Mai 2006)

Hallo Group,

ich (C++ newbie) habe folgendes Problem:

Ich habe eine Basisklasse von der viele spezielle Klassen abgeleitet werden.
In der Basisklasse soll eine Methode ausgeführt werden, die dann beliebige Methoden in beliebigen abgeleiteten Klassen als Thread ausführen kann. Die sollte so geschehen, damit sich nicht jeder Programmierer um das Aufrufen eines Threads kümmern muss.
Um Threads zu starten nutze ich die pthread-Library. Beispiel:



```
//Thread starten
pthread_t threads[1];
pthread_create(&threads[0], NULL, Threadstart, this); 

//pthread kann nur diese Methodenköpfe (void* Methodenname (void *This)) adressieren
void * Threadstart(void *This)
{
      //Im Thread ausgeführte Methode	 
      bestandsAnfrage(4); 
}
```

Wie kann ich das Aufrufen des Threads in eine Basisklasse verlagern? Ich müsste in der Basisklasse doch so etwas definieren:


```
void * starteThreadVonSubKlasse(Aufzurufendes Objekt, Aufzurufende Methode)
{
     pthread_create(&threads[0], NULL, Aufzurufendes Objekt -> Aufzurufende Methode, this); 
}
```

Kann ich den Thread überhaupt so starten? Kann ich die Adresse von einem Objekt + Methode übergeben? Habe das schon mehrmals (ohne Erfolg) probiert.

Es würde mich freuen, wenn es eine Lösung dafür gäbe. Es kann ja nicht sein, dass sich in einem Programm jeder Programmierer um das Aufrufen eines Threads selbst kümmern muss. 

Viele Grüße,

Jens Hibbeler


----------



## Jens Hibbeler (15. Mai 2006)

Hallo,

ich habe mein Beispiel für die Basisklasse noch einmal überdacht und verbessert:


```
//Struktur, um Objekt und Methode zu übergeben, da pthread_create nur einen Aufrufparameter im Methodenkopf akzeptiert
struct Uebergabe
{
    Aufzurufendes Objekt a;
    Aufzurufende Methode b;
}
 
//Die Methode, in der die Methode der Subklasse aufgerufen wird:
void * Threadstart(void *This)
{
        //Cast nach Uebergabe
        Uebergabe UebergabeNeu=(Uebergabe *) This;
 
        //Aufruf der Methode der Subklasse
        UebergabeNeu.a->UebergabeNeu.b;
}
 
//Die Methode, die den Thread startet
void * starteThreadVonSubKlasse(void *This)
{
     pthread_create(&threads[0], NULL, Threadstart , Uebergabe); 
}
```

Jedoch stellen sich dann die Fragen:
Kann ich die Adresse von einem Objekt + Methode so übergeben? Wie muss ich die Methodenköpfe und die Datentypen der Struktur definieren?

Viele Grüße,

Jens Hibbeler


----------



## RedWing (15. Mai 2006)

Hallo,

man kann keine Funktionszeiger auf Objektmethoden zeigen lassen, nur auf Klassenmethoden,
sprich also wenn du deine Methoden als static deklarierst...

Dein Ansatz war schon ok... Was haelst du von folgendem Vorschlag:


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

using namespace std;

enum MethodFlag{ADD, SUB};

class Abstract{
	public:		
	void method(MethodFlag flag){
		if(flag == ADD)
			add();
		else
			sub();
	}
	virtual void add() = 0;
	virtual void sub() = 0;
};

class Concrete1 : public Abstract{
	private:
	void add(){
		cout << "Concrete1: add" << endl;
	}
	
	void sub(){
		cout << "Concrete1: sub" << endl;
	}
};

class Concrete2 : public Abstract{
	private:
	void add(){
		cout << "Concrete2: add" << endl;
	}
	
	void sub(){
		cout << "Concrete2: sub" << endl;
	}
};

struct data_t{
	MethodFlag mf;
	Abstract* object;
};

void* thread_r(void* data){
	data_t* t = static_cast<data_t*>(data);
	t->object->method(t->mf);
	return data;
}

int main(){
	pthread_t thread[1];
	Abstract* a1 = new Concrete1();
	Abstract* a2 = new Concrete2();
	data_t user_data[] = {{ADD, a1}, {SUB, a2}};
	pthread_create(thread, NULL, thread_r, &user_data[0]);
	pthread_create(thread, NULL, thread_r, &user_data[1]);
	sleep(1);
        delete a1;
        delete a2;
}
```

Die sleep Anweisung is nat. unschoen, ist aber nur zu Testzwecken gemacht...

Gruß

RedWing


----------



## Jens Hibbeler (15. Mai 2006)

Hallo,

entschuldige, dass ich Dir jetzt erst antworte, aber ich habe versucht Deinen Vorschlag umzusetzen. Was mir noch nicht gefällt, ist das Mapping der Methoden per Flag.
Ich finde Deinen Vorschlag aber sehr gut -hat mich auf eine neue Idee gebracht und ich versuche diese mal zu implementieren. 
Ich denke morgen am späten Nachmittag werde ich an dieser Stelle schon mehr sagen können.
Das Problem scheint aber allgemein zu sein, da es mehrere haben.

Viele Grüße und Dank,

Jens Hibbeler


----------



## Jens Hibbeler (16. Mai 2006)

Hallo,

meine Lösung sieht jetzt so aus, dass ich den das Starten des Threads in die Basisklasse verlagert habe. Diese ruft dann statische Funktionen der Abgeleiteten Klassen auf und führt diese in einem Thread aus. Habe ich so gemacht, da pthread nur c-Funktionen ausführen kann.
Damit der Objektbezug nicht verloren geht, schleife ich in einer Struktur noch immer eine Instanz des Objekts mit.

Beispiel (so in etwa):

```
Basisklasse:
class BackendAdapter  {

public:void starteBackendThread(void *(*MethodenName) (void *), void *arg );
		
};
```


```
Abgeleitete Klasse
class BackendAdapterArtikelPosition{
void *  BackendAdapterArtikelPosition::bestandsAnfrage (void *arg)//, HWND hWnd)
{
struct bestandsAnfrageRequest *temp=(bestandsAnfrageRequest *) arg;
//Mache was mit dem Objekt	
temp->temp;
...
}
};
```

und dann in der Klasse die das Ganze benutzt:

```
BAAPI->bestAnfrageReq.temp=BAAPI;
 BAAPI->starteBackendThread(BackendAdapterArtikelPosition::bestandsAnfrage, (void*)&BAAPI->bestAnfrageReq);
```

Ich hoffe das funktioniert. War jetzt auf die Schnelle ohne zu testen.
Vorteil:
-Kein Mapping auf die Methoden
-Threads werden in der Basisklasse gestartet
-Keine extra C-Funktionen nötig, die C++ Funktionen starten

Nachteil:
-Parameterübergabe für Methoden erfolgt nur über Structs
-Objekte müssen duchgeschliffen werden, damit der Bezug nicht verloren geht

Danke für Deine schnelle Hilfe!

Viele Grüße,

Jens


----------

