Windows Azure Cloud Storage ermöglicht es Ihnen bereits ab 0,10€ pro GB/Monat die Vorteile der Cloud zu nutzen. Bring Deine App nach vorne.
Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Advanced Developers Conference     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: VCL (C++ Builder) ::  Wie erstellt man einen neuen Thread?  
Gehen Sie zu Seite Zurück  1, 2, 3, 4  Weiter
  Zeige alle Beiträge auf einer Seite
Auf Beitrag antworten
Autor Nachricht
sonic_1233
Mitglied

Benutzerprofil
Anmeldungsdatum: 30.06.2008
Beiträge: 276
Beitrag sonic_1233 Mitglied 08:37:51 10.02.2010   Titel:              Zitieren

In diesem Forum gibt es anscheinend ein Tutorial für Threads:

http://bcb-tutorial.c-plusplus.de/Thread/artikel5.html

Ich glaube da ist ein Fehler drin.
Dort wird im Thread-Konstruktor FreeOnTerminate auf true gesetzt. Das bedeutet doch, dass der Thread nach der Ausführung von "Execute" sich selbstständig terminiert. Und in der Cleanup-Funktion wird "Terminate()" aufgerufen. Das ist doch überflüssig, oder?

_________________
Das Problem ist uns bekannt. Wir arbeiten daran und rechnen mit einer baldigen Lösung.
Unregistrierter





Beitrag Unregistrierter 10:59:54 10.02.2010   Titel:              Zitieren

@sonic:
Ich habe mir das Tutorial jetzt nicht angesehen, aber der Aufruf von Terminate() beendet einen Thread. Wenn FreeOnTerminate=true ist, muss man weiter nichts machen. Wenn es false ist, muss man den Thread auch noch löschen.
Der Aufruf von Terminate() ist nicht grundsätzlich verboten, auch wenn der Thread mit FreeOnTerminate=true ist. Es gibt Threads die laufen in einer kontunierlichen Schleife, diese muss man mit Terminate() beenden. Wenn ein Thread allerdings eine eigene Abbruchbedingung hat, sollte man Terminate() nicht verwenden.

@audacia
Der bleibt in der Zeile 19, also dem WaitResult := ... stehen. Zumindest ist das die aufrufende Funktion. Viel häufiger wird mir allerdings der Aufruf von Sleep als aufrufende Funktion angezeigt (in 9 von 10 Fällen).
Das verstehe ich dann jetzt überhaupt nicht. Ich mein, es ist nur ein 200 ms Sleep, wie kann das mehrere Sekunden beanspruchen?!? Könnte das an meiner Hardware liegen? Der Rechner ist zugegebenermaßen schon ziemlich alt.
DocShoe
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.04.2008
Beiträge: 1484
Beitrag DocShoe Mitglied 12:26:51 10.02.2010   Titel:              Zitieren

Joe_M. schrieb:

@audacia
Der bleibt in der Zeile 19, also dem WaitResult := ... stehen. Zumindest ist das die aufrufende Funktion. Viel häufiger wird mir allerdings der Aufruf von Sleep als aufrufende Funktion angezeigt (in 9 von 10 Fällen).
Das verstehe ich dann jetzt überhaupt nicht. Ich mein, es ist nur ein 200 ms Sleep, wie kann das mehrere Sekunden beanspruchen?!? Könnte das an meiner Hardware liegen? Der Rechner ist zugegebenermaßen schon ziemlich alt.


Wir hatten bei einem Projekt genau das gleiche Verhalten, nur dass es nicht 7 Sekunden, sondern 30+ waren. Das Szenario war das gleiche, im Destruktor des TThreads blieb die CPU auf WaitFor stehen. Das Verhalten war nicht immer 100%ig (eigentlich war das korrekte Verhalten nicht reproduzierbar, in 4 von 5 Fällen hing der Thread im Destruktor) reproduzierbar, es trat sowohl auf zwei Entwicklungsrechnern als auch auf einem Produktionssystem auf.
Chrisi_K
Mitglied

Benutzerprofil
Anmeldungsdatum: 08.08.2002
Beiträge: 29
Beitrag Chrisi_K Mitglied 15:24:02 10.02.2010   Titel:              Zitieren

Hallo

Das Problem mit dem blockieren im WaitFor des Threads liegt darin, dass WaitFor intern einen Sleep(0) verwendet. Dieser gibt den Prozessor nur an Threads mit gleicher Priorität ab.
Wenn auf einen Thread mit tieferer Priorität gewartet wird, erhält dieser keine CPU-Zeit (ausser auf Mehr-Prozessor-Systemen).
Zur Abhilfe sollte die Priorität des Threads, auf den gewartet wird vor dem WaitFor (oder vor Terminate) auf mindestens die Priorität des aktuellen Threads angehoben werden.

Gruss Chis
Unregistrierter





Beitrag Unregistrierter 15:42:51 10.02.2010   Titel:              Zitieren

Ich bin sprachlos. Mit einem Priority = tpHigher vor der Terminate()-Aufruf, ist das Problem tatsächlich weg. Was hab ich damals nicht alles probiert, aber darauf bin ich nicht gekommen...

Aber im Beispiel zu Priority wird die Priorität gesetzt, bevor der Thread mit Resume fortgesetzt ist. Ist das nur Zufall, oder soll das ein Hinweis darauf sein, dass man die Priorität zur Laufzeit nicht ändern sollte?
Chrisi_K
Mitglied

Benutzerprofil
Anmeldungsdatum: 08.08.2002
Beiträge: 29
Beitrag Chrisi_K Mitglied 16:05:28 10.02.2010   Titel:              Zitieren

Ich habe schon öfters Thread-Prioritäten zur Laufzeit geändert. Konnte bisher nie irgendein Nachteil feststellen. In der Doku habe ich auch keine Hinweise gefunden, die dies als schlecht einstufen.

Gruss Chris
audacia
Mitglied

Benutzerprofil
Anmeldungsdatum: 05.02.2005
Beiträge: 3802
Beitrag audacia Mitglied 19:48:47 10.02.2010   Titel:              Zitieren

Chrisi_K schrieb:
Das Problem mit dem blockieren im WaitFor des Threads liegt darin, dass WaitFor intern einen Sleep(0) verwendet. Dieser gibt den Prozessor nur an Threads mit gleicher Priorität ab.
Wenn auf einen Thread mit tieferer Priorität gewartet wird, erhält dieser keine CPU-Zeit (ausser auf Mehr-Prozessor-Systemen).
Tatsächlich - ist ja auch so in der Dokumentation zu Sleep() nachlesbar. *facepalm*


Zu dem Problem gibt es auch schon einen QC-Report: #3260. Allerdings sollte das Problem mittlerweile nicht mehr auftreten, denn in C++Builder 2006 und höher verwendet TThread.WaitFor kein Sleep(0) mehr:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function TThread.WaitFor: LongWord;
{$IFDEF MSWINDOWS}
var
  H: array[0..1] of THandle;
  WaitResult: Cardinal;
  Msg: TMsg;
begin
  H[0] := FHandle;
  if GetCurrentThreadID = MainThreadID then
  begin
    WaitResult := 0;
    H[1] := SyncEvent;
    repeat
      { This prevents a potential deadlock if the background thread
        does a SendMessage to the foreground thread }
      if WaitResult = WAIT_OBJECT_0 + 2 then
        PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
      WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
      CheckThreadError(WaitResult <> WAIT_FAILED);
      if WaitResult = WAIT_OBJECT_0 + 1 then
        CheckSynchronize;
    until WaitResult = WAIT_OBJECT_0;
  end else WaitForSingleObject(H[0], INFINITE);
  CheckThreadError(GetExitCodeThread(H[0], Result));
end;
{$ENDIF}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function TThread.WaitFor: LongWord;
{$IFDEF MSWINDOWS}
var
H: array[0..1] of THandle;
WaitResult: Cardinal;
Msg: TMsg;
begin
H[0] := FHandle;
if GetCurrentThreadID = MainThreadID then
begin
WaitResult := 0;
H[1] := SyncEvent;
repeat
{ This prevents a potential deadlock if the background thread
does a SendMessage to the foreground thread }
if WaitResult = WAIT_OBJECT_0 + 2 then
PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
CheckThreadError(WaitResult <> WAIT_FAILED);
if WaitResult = WAIT_OBJECT_0 + 1 then
CheckSynchronize;
until WaitResult = WAIT_OBJECT_0;
end else WaitForSingleObject(H[0], INFINITE);
CheckThreadError(GetExitCodeThread(H[0], Result));
end;
{$ENDIF}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function TThread.WaitFor: LongWord;
{$IFDEF MSWINDOWS}
var
  H: array[0..1] of THandle;
  WaitResult: Cardinal;
  Msg: TMsg;
begin
  H[0] := FHandle;
  if GetCurrentThreadID = MainThreadID then
  begin
    WaitResult := 0;
    H[1] := SyncEvent;
    repeat
      { This prevents a potential deadlock if the background thread
        does a SendMessage to the foreground thread }
      if WaitResult = WAIT_OBJECT_0 + 2 then
        PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
      WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
      CheckThreadError(WaitResult <> WAIT_FAILED);
      if WaitResult = WAIT_OBJECT_0 + 1 then
        CheckSynchronize;
    until WaitResult = WAIT_OBJECT_0;
  end else WaitForSingleObject(H[0], INFINITE);
  CheckThreadError(GetExitCodeThread(H[0], Result));
end;
{$ENDIF}


Das erklärt zwar nicht, weshalb ich das Problem mit C++Builder 6 nicht reproduzieren kann (SetProcessAffinityMask() habe ich natürlich getestet), aber in neueren Versionen sollte es nicht mehr auftreten.

_________________
"Hey, it compiles! Ship it!"
C++Builder Pages · Typsichere Format-Strings
Killer-Kobold
Mitglied

Benutzerprofil
Anmeldungsdatum: 16.03.2009
Beiträge: 180
Beitrag Killer-Kobold Mitglied 20:57:43 10.02.2010   Titel:              Zitieren

audacia schrieb:

Das erklärt zwar nicht, weshalb ich das Problem mit C++Builder 6 nicht reproduzieren kann (SetProcessAffinityMask() habe ich natürlich getestet), aber in neueren Versionen sollte es nicht mehr auftreten.


Hast Du mehr als einen CPU-Kern im Rechner?
audacia
Mitglied

Benutzerprofil
Anmeldungsdatum: 05.02.2005
Beiträge: 3802
Beitrag audacia Mitglied 00:54:16 11.02.2010   Titel:              Zitieren

Zwei, sonst wäre SetProcessAffinityMask() redundant ;)
Das wird sicherlich auch die Ursache sein; allerdings ist mir noch nicht ganz klar, weshalb sich das Problem nicht mit SetProcessAffinityMask() reproduzieren läßt. (Vielleicht arbeitet der Thread-Scheduler auf Mehrkernsystemen grundsätzlich anders? Mal in Windows Internals nachlesen.)

_________________
"Hey, it compiles! Ship it!"
C++Builder Pages · Typsichere Format-Strings
sonic_1233
Mitglied

Benutzerprofil
Anmeldungsdatum: 30.06.2008
Beiträge: 276
Beitrag sonic_1233 Mitglied 09:32:35 11.02.2010   Titel:              Zitieren

Hallo,

ich habe noch eine Frage zum Thema Thread-Erstellung.
Ich habe einen Thread, in dessen Execute-Funktion ein Button aufgerufen wird.
Die Funktion in diesem Button schreibt Daten in eine TStringGrid rein. In der OnDrawCell von dieser StringGrid
färbe ich die Zellen abhängig von den Zelleninhalten.
Jetzt kriege ich sporadisch Fehlermeldungen "Zugriffsverletzung an der Adresse xxx" oder "Falsche Zeigeroperation". Der Fehler wird durch
den Zugriff auf den Zelleninhalt ausgelöst. Das habe ich mit dem Debugger geprüft.

Kann es sein, dass die OnDrawCell() mit meinem Thread irgendwie synchronisiert werden muss? Weil sie ja im Hauptthread
aufgerufen wird. Oder die StringGrid ist nicht Thread-sicher

_________________
Das Problem ist uns bekannt. Wir arbeiten daran und rechnen mit einer baldigen Lösung.


Zuletzt bearbeitet von sonic_1233 am 09:42:46 11.02.2010, insgesamt 1-mal bearbeitet
C/C++ Forum :: VCL (C++ Builder) ::  Wie erstellt man einen neuen Thread?  
Gehen Sie zu Seite Zurück  1, 2, 3, 4  Weiter
Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.