Forum: PC-Programmierung Verstehe Fehlermeldung von Visual Studio C++ 2005 nicht


von Tiger (Gast)


Lesenswert?

Guten Morgen,

ich hab eine Klasse "Thread" in der ich alle Funktionen zum starten bzw. 
stoppen eines Threads benötigt werden. Diese Klasse habe ich nun 
abgeleitet, so dass ich in der Klasse "CSerialPortChild" auf die 
"virtuelle Methode" mit dem Namen "void ThreadFunction(void*);" 
zugreifen kann.

Headerdatei "CSerialPortChild.h":
1
typedef struct Srecv STrecv;
2
struct Srecv 
3
{  
4
  char receive[1024];
5
  int len;
6
};
7
8
class CSerialPortChild: public CSerialPort, public Thread
9
{                             
10
public:
11
  
12
  STrecv recv;
13
14
  // contruction and destruction
15
  CSerialPortChild();
16
  ~CSerialPortChild();
17
  void ThreadFunction(void*);
18
19
protected:
20
    
21
22
};
23
24
#endif

Quelldatei "CSerialPortChild.cpp"
1
CSerialPortChild::CSerialPortChild():CSerialPort()
2
{
3
4
}
5
6
7
CSerialPortChild::~CSerialPortChild()
8
{
9
10
}
11
12
13
void CSerialPortChild::ThreadFunction(void* ptr)
14
{
15
  Srecv *precv= (Srecv*)ptr;
16
17
  while(true)
18
  {
19
    precv->len = 0;
20
21
22
  }
23
24
}

Nun möchte ich in der Methode "ThreadFunction" auf die Variablen 
"receive" und "len" zugreifen. Wenn ich es so mache, wie oben gezeigt 
dann erscheint folgende Fehlermeldung:

Unbehandelte Ausnahme bei 0x00411b35 in ComTerm.exe: 0xC0000005: 
Zugriffsverletzung beim Schreiben an Position 0xcdcdd1cd.


Aufrufliste:
-ComTerm.exe!CSerialPortChild::ThreadFunction(void * ptr=0xcdcdcdcd) 
Zeile 28 + 0x3 Bytes  C++
-ComTerm.exe!Thread::my_Thread(void * para=0x0031beb0)  Zeile 51 + 0x15 
Bytes  C++

von Karl H. (kbuchegg)


Lesenswert?

Tiger schrieb:

> -ComTerm.exe!CSerialPortChild::ThreadFunction(void * ptr=0xcdcdcdcd)

                                                           **********

Du übergibst eine ungültige Adresse.
Der Fehler liegt also beim Aufrufer.

von Klaus W. (mfgkw)


Lesenswert?

Da fehlt noch einiges an Quelltext.
Wo ist der Start des Threads? Was wird da übergeben?

Außerdem sollte in einer Klasse, in der mindestens eine virtuelle
Methode ist, IMMER der Destruktor auch virtuell sein.
Hat damit nichts zu tun, aber fiel mir so auf.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> Da fehlt noch einiges an Quelltext.
> Wo ist der Start des Threads? Was wird da übergeben?
>
> Außerdem sollte in einer Klasse, in der mindestens eine virtuelle
> Methode ist, IMMER der Destruktor auch virtuell sein.
> Hat damit nichts zu tun, aber fiel mir so auf.

Weiters:
Wenn eine Funktion in der Basisklasse virtual ist, sollte man die 
gleichnamige Funktion in der abgeleiten Klasse ebenfalls explizit 
virtual machen.

von Klaus W. (mfgkw)


Lesenswert?

ja, wobei das nur zur Klarheit ist; virtual ist sie sowieso.

von Tiger (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab den gesamten Quellcode hochgeladen. Ich weiss da nicht mehr 
weiter.
Für jede Hilfe sag ich schonmal vielen Dank!

von Klaus W. (mfgkw)


Lesenswert?

bin raus, ich kann kein rar

von Tiger (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab die Dateien nun mit Zip gepackt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Wenn ich es so mache, wie oben gezeigt
> dann erscheint folgende Fehlermeldung:
>
> Unbehandelte Ausnahme bei 0x00411b35 in ComTerm.exe: 0xC0000005:
> Zugriffsverletzung beim Schreiben an Position 0xcdcdd1cd.

...

Wenn Du das im Debugger laufen lässt, dann siehst Du auch, wie die 
Funktion mit welchen Parametern aufgerufen wurde. Wie schon von Karl 
Heinz beschrieben, ist der Pointer, der "ThreadFunction" übergeben 
wurde, nicht initialisiert.


Der von Dir gepostete Code ist übrigens unvollständig, es fehlt 
"SerialPortChild.cpp".

- auch im ZIP-Archiv.

von Karl H. (kbuchegg)


Lesenswert?

Du brauchst doch nur am Call Stack zurückgehen und dir ansehen, wer die 
ThreadFunction aufruft und welches Argument er ihr mitgibt. Die nächste 
Frage ist dann, wo kommt dieses Argument her und warum wurde es nie 
initialisiert.

Wenn du dich mit Threads beschäftigst, solltest du solche Dinge schon 
können. Ansonsten treiben dich die schwierigeren Dinge bei Threading in 
den Wahnsinn.

von Tiger (Gast)


Angehängte Dateien:

Lesenswert?

Hab sie ausversehen vergessen mit reinzunehmen.

von Tiger (Gast)


Lesenswert?

Und wie müsste ich den Pointer von der Methode "ThreadFunction" 
initialisieren?

von Klaus W. (mfgkw)


Lesenswert?

ist das die SerialPortChild.cpp?
Glaube, mein Zipper ist kaputt.

von Karl H. (kbuchegg)


Lesenswert?

Tiger schrieb:
> Und wie müsste ich den Pointer von der Methode "ThreadFunction"
> initialisieren?


Je nachdem was du eigentlich machen willst.

Im Moment wird die Threadfunction aufgerufen und ihr der Callbackpointer 
mitgegeben m_callback. Der kriegt aber nie einen Wert (ausser NULL). Und 
damit geht dann der Zugriff precv->len = 0; mächtig in die Hose.

Da dein Stack Trace einen Pointer Wert von 0xcdcdcdcd zeigt, in dem von 
dir geposteten Code m_callback aber auf 0 initialisiert wird und ich bei 
mir im Debugger den Pointer auch tatsächlich als 0x000000 sehe, gehe ich 
davon aus, dass du den Code seit deinem ersten Post verändert hast.


Mach dich mit deinem Debugger vertraut! Der ist der Helfer in der Not. 
Ohne mit ihm umgehen zu können, brauchst du nicht weitermachen.

von Klaus W. (mfgkw)


Lesenswert?

Wo ist denn nun der Start des Threads? Dort kann man doch einen
Parameter angeben (void* oder LPVOID oder sowas), der an die
Threadfunktion durchgereicht wird. Und genau da müsstest du
die Adresse deiner Struct übergeben.

von Tiger (Gast)


Lesenswert?

Danke für eure Hilfe. Ich weiss nicht wo ich wie und was übergeben muss.
Ich bin jetzt total durcheinander.

von Karl H. (kbuchegg)


Lesenswert?

> Ich weiss nicht wo ich wie und was übergeben muss.
Müssen tust du gar nichts.
Du bist der Boss, du entscheidest, welche Daten wo in welche Funktion 
übergeben werden. Aber kein Mensch schreibt dir vor, was du tun musst.


Lass mich raten.

Code von irgendwo her kopiert. Nicht duchgeschaut und auch noch keinen 
Versuch gemacht das zu verstehen.

So funktioniert Programmieren nicht. Klar kann man Code von irgendwo her 
kopieren. Aber man muss ihn auch verstehen. Und das mindeste ist es, im 
Debugger einmal duchzusteppen.

von Tiger (Gast)


Lesenswert?

Nein dem ist nicht so. Ich hab mal vor einiger Zeit mit einem 
Echtzeitbetriebssystem zu tun gehabt.

von Karl H. (kbuchegg)


Lesenswert?

Tiger schrieb:
> Nein dem ist nicht so. Ich hab mal vor einiger Zeit mit einem
> Echtzeitbetriebssystem zu tun gehabt.

Jetzt bin ich verwirrt.

Du schreibst einen relativ banalen 100-Zeiler und blickst dann selbst 
nicht mehr durch, warum eine Funktion einen ungültigen Pointer bekommt?

von Tiger (Gast)


Lesenswert?

1
DWORD WINAPI Thread::my_Thread(void* para)
2
{
3
    Thread* pthis=(Thread*)para;
4
  int t;
5
  if(pthis!=NULL)
6
  {
7
    pthis->ThreadFunction(pthis->m_callback);
8
    t=9;
9
    return 0;
10
  }
11
  return -1;
12
}

Was ist hier bitte schön falsch daran? Sorry, wenn ich euch damit nerve.
Ich hab nur ganz normal um Hilfe gebeten.

von Tiger (Gast)


Lesenswert?

Den Thread starte ich damit:
1
hThread = CreateThread(NULL, Thread_STACK_SIZE, my_Thread, this, 0, &dwThreadID);

Wo müsste ich da noch einen Pointer übergeben?

von Klaus W. (mfgkw)


Lesenswert?

So, und wenn ich das richtig sehe, ist der vierte Parameter
(bei dir: this) das, was als void-Parameter an die
Threadfunktion weitergereicht wird.
Darin castet du das in einen Zeiger auf eine struct, was natürlich
schief geht.

Wenn ich jetzt nicht falsch liege, müsstest du als 4. Parameter die
Adresse der gewünschten struct angeben.

Was hattest du mit dem this an dieser Stelle vor?

von Tiger (Gast)


Lesenswert?

Hallo Klaus Wachtler,

danke für den Rat. Allerdings weiss die Klasse Thread ja nicht, dass die 
Klasse CSerialPortChild eine Struktur besitzt. Wie kann man trotz all 
dem eine Adresse übergeben?

von Klaus W. (mfgkw)


Lesenswert?

Dazu müsste man wissen, wie deine Objekte zusammenhängen und wie
alles zusammen spielen soll. Eigentlich müsstest du das wissen;
ich habe gerade keine besondere Lust, das aus einem
undokumentierten Quelltext zu rekonstruieren.

Rein technisch geht es notfalls über eine globale Variable, die
jemand vorher setzt (sicher der schlechteste Weg), oder irgendwelche
get- oder set-Methoden, über die Thread das rechtzeitig erfährt.

von UserX (Gast)


Lesenswert?

Klaus Wachtler (mfgkw) schrieb:
>bin raus, ich kann kein rar

In welchem Jahrhundert lebst du denn?
Rar gibt's doch heutzutage für alle Systeme.

von Klaus W. (mfgkw)


Lesenswert?

Gibt es sicher, aber ist auf meinem Rechner nicht drauf.
Und ehrlich gesagt muß ich auch nicht jedes obskure Datenformat
handhaben, solange es ein paar verbreitete und frei zugängliche
Formate gibt. RAR ist meines Wissens nicht frei (zumindest das
Komprimieren).
Warum nicht ZIP?

von Karl H. (kbuchegg)


Lesenswert?

Tiger schrieb:
>
1
> 
2
> DWORD WINAPI Thread::my_Thread(void* para)
3
> {
4
>     Thread* pthis=(Thread*)para;
5
>   int t;
6
>   if(pthis!=NULL)
7
>   {
8
>     pthis->ThreadFunction(pthis->m_callback);
9
>     t=9;
10
>     return 0;
11
>   }
12
>   return -1;
13
> }
14
> 
15
>
>
> Was ist hier bitte schön falsch daran?

Da ist gar nichts falsch daran.

pthis->m_callback wird übergeben.

Aber pthis->m_callback wird nie auf einen Wert gesetzt!
Das würde über einen Aufruf von SetCallback gemacht, aber die Funktion 
wird nie aufgerufen.

Schuss ins Blaue:

CSerialPortChild::CSerialPortChild():CSerialPort()
{
  SetThreadCallBack( &this->recv );
}

Aber eigentlich müsstest DU das wissen. Du hast es ja designed.

von Tiger (Gast)


Lesenswert?

Ich hab auch mein Fehler entdeckt. So funktioniert es:
1
CSerialPortChild::CSerialPortChild():Thread()
2
{
3
  recv.len = 0;
4
  SetThreadCallBack((void*)&recv );
5
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.