ich möchte in einer Anwendung, die ich mit in BCB 5.0 Pro erstellt habe, einen Thread erstellen.
Gibt es hier, im Forum, eine Anleitung dazu? Ich finde nichts dazu
_________________ Das Problem ist uns bekannt. Wir arbeiten daran und rechnen mit einer baldigen Lösung.
Wenn das ein reiner Worker Thread ohne Interaktion mit der Benutzeroberfläche sein soll würde ich lieber Win32 Threads benutzen. Die aus der VCL haben so komische Randbedingungen, die erfüllt sein müssen (z.B. beim Stoppen). Die dazu notwendigen Funktionen heissen CreateThread, SuspendThread, ResumeThread und TerminateThread.
Also ich habe jetzt was zusammengebaut. In einer Timerfunktion erstelle ich alle 100 ms einen neuen Thread. Es läuft auch eine Zeit lang gut. Nach etwa 2 Minuten wird das Programm immer langsamer, und dann kommt die Fehlermeldung "Abnormal termination".
Ich denke, dass die erstellten Threads nicht richtig beendet werden.
Weiss vielleicht jemand von euch, was ich falsch gemacht habe?
Die aus der VCL haben so komische Randbedingungen, die erfüllt sein müssen (z.B. beim Stoppen).
Was meinst du?
Für einen Worker-Thread ist das okay, aber ansonsten ist der Verzicht auf Synchronize() und Queue() IMO unangenehm.
DocShoe schrieb:
Die dazu notwendigen Funktionen heissen CreateThread, SuspendThread, ResumeThread und TerminateThread.
Da muß ich gleich dreimal entschieden widersprechen.
CreateThread sollte in C- und C++-Programmen nicht verwendet werden, da die C-RTL threadweise initialisiert werden muß. Darauf weist unter anderem die Dokumentation im MSDN hin:
MSDN schrieb:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multi-threaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
Das ist in der C++Builder-RTL nicht anders.
Der einzige legitime Grund zur Verwendung von ResumeThread ist das Starten eines mit CREATE_SUSPENDED erstellten Threads. Ansonsten ist die Verwendung von SuspendThread und ResumeThread dringend zu vermeiden, denn das kann zu völlig unvorhersehbaren Deadlocks führen, wenn der Thread gerade ein Lock auf irgendeine Ressource hält. Auch das ist im MSDN nachzulesen:
MSDN schrieb:
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.
Schließlich ist TerminateThread mit Sicherheit von allen Lösungen, einen Thread zu beenden, die schlechteste. Du findest dazu auch etwa auf StackOverflow Hinweise, aber auch hier ist MSDN sehr explizit:
MSDN schrieb:
TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code. DLLs attached to the thread are not notified that the thread is terminating. The system frees the thread's initial stack.
Windows Server 2003 and Windows XP/2000: The target thread's initial stack is not freed, causing a resource leak.
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
If the target thread owns a critical section, the critical section will not be released.
If the target thread is allocating memory from the heap, the heap lock will not be released.
If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
Die richtigen Alternativen sind _beginthread()/_beginthreadex(), die Event-Funktionen im Windows-API sowie ein derartiges Thread-Design, daß der gewünschte Abbruch durch ein Event signalisiert werden kann. Oder, wenn du es einfach haben willst, einfach ein Wrapper wie TThread.
In einer Timerfunktion erstelle ich alle 100 ms einen neuen Thread.[...]Weiss vielleicht jemand von euch, was ich falsch gemacht habe?
Du hast das Tutorial nicht durchgelesen.
Wie im MSDN einzusehen ist, wird für jeden erstellten Thread etwa 1 MB für den Stack bereitgestellt. Das macht bei dir etwa 10 MB pro Sekunde. Jetzt noch einkalkuliert, daß eine gewöhnliche 32-Bit-Anwendung maximal knapp 2 GB virtuellen Arbeitsspeicher zugewiesen bekommen kann, und du kannst ausrechnen, daß deine Anwendung nach spätestens 3:41 Minuten keinen Adreßraum mehr zur Verfügung hat. In der Realität tritt das natürlich früher ein, weil der Adreßraum ja nicht nur für deine Threads da ist.
MSDN schrieb:
The number of threads a process can create is limited by the available virtual memory. By default, every thread has one megabyte of stack space. Therefore, you can create at most 2,048 threads. If you reduce the default stack size, you can create more threads. However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue.
Anders gesagt, erstelle einen einzigen Thread, der auf Anweisungen wartet (WaitForSingleObject), sie abarbeitet, dem UI-Thread mittels TThrea::Synchronize() das Ergebnis übergibt und dann von vorne anfängt.
Es ist nicht sinnvoll, mit Threads einfach so draufloszuprogrammieren, ohne sich zuvor informiert zu haben. Multithreading gehört mit zu den komplexesten Systemabläufen, mit denen sich ein Anwendungsprogrammierer auseinandersetzen muß; wenn du dich nicht gut vorbereitest, wirst du nie in der Lage sein, die unvermeidlichen multithreading-verursachten Abstürze in deiner Anwendung zu beheben. Also reiß dich zusammen und arbeite das Tutorial durch, bevor du fortfährst.
Also reiß dich zusammen und arbeite das Tutorial durch, bevor du fortfährst.
Ach was, wann hat man sonst die Möglichkeit, so schöne Fehlermeldungen, wie 'Leinwand erlaubt kein zeichnen' zu erhalten.
Ich hab mit den VCL-Threads aber auch so meine Probleme. Ich hab keine Möglichkeit gefunden, laufende Threads, mit VCL-Mitteln, sinnvoll zu beenden, wenn der User die Anwendung beendet. Da muß man tatsächlich auf Events und WaitForXXX zurückgreifen. Oder ich hab mich wieder zu blöd angestellt...
Ich habe das Thema wohl auf die leichte Schulter genommen. Aber nur, weil
mein Chef alles am besten gestern fertig haben will.
Danke für alle Kommentare. Ich werde gleich das Tutorial durchlesen.
_________________ Das Problem ist uns bekannt. Wir arbeiten daran und rechnen mit einer baldigen Lösung.
@Audacia
Ich habe nur die 4 wichtigsten Funktionen zur Win32 Threadverwaltung genannt, vielleicht bin ich fälschlicherweise davon ausgegangen, dass der OP sich mit Thread Design und Verhinderung von race conditions auskennt (die man im übrigen auch mit TThread haben kann). Ich stimme dir insofern zu, dass man die Techniken zur Threadsynchronisation beherrschen muss, um mit den Win32 API Funktionen ein robustes Thread Design zu erstellen.
Das Verhalten eines von TThread abgeleiteten Threads kann mitunter schon seltsam sein, insbesondere wenn ein Thread gestoppt werden soll, der noch nie gelaufen ist. Im Destruktor ~TThread() wird allerhand Synchroniasationszeugs getrieben, wobei es bei uns schon bis zu 30 Sekunden gedauert hat, bis die CPU aus dem Destruktoraufruf zurückgekommen ist. Leider konnten wir die genauen Randbedingungen nie vollständig ermitteln, aber ein Wechsel von TThread auf Threads durch die Win32 API hat das Problem instantan gelöst.
Wie du schon erwähntest steht man dann aber vor dem Problem, dass man aus den Win32 Threads keine GUI Aktualisierung anstossen kann (jedenfalls nicht durch direkte Methodenaufrufe irgendwelcher VCL Objekte), da die VCL kein Multithreading beherrscht und von sich aus auch keine Hilfsmitteln anbietet, um sich mit nicht VCL-Threads zu synchronisieren. Ich denke aber, dass man eine Synchronisation mit benutzerdefinierten Nachrichten und PostMessage hinbekommt.
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.
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.