C++ Thread schlafen schicken \ wecken

Legenbaer

Cadet 4th Year
Registriert
Juni 2006
Beiträge
108
Hallo Leute,

ich bin gerade dabei mich mit Threads zu beschäftigen, da ich ne Menge parallelisierbarer Berechnungen habe. Derzit ist es so, dass für jede Berechnung (Euklidischer Abstand) ein Thread erstellt wird, welcher durchläuft und sich dann wieder schliesst. Das ist allerdings langsamer als das direkte Ausfürhren des Codes ohne die Auslagerung in einen Thread. Ich vermute, weil eben immer ein neuer Thread erstellt werden muss.

Mein Frage ist daher, wie ich einen Thread "einschläfern" kann und wieder wecken wenn ich ihn brauche?!?!

Die grobe Art und weise wie ich das bisher geschrieben habe ist...

Code:
struct ThreadContainer
{
	LPDWORD ThreadID;
	int			from;
	int			to;
};

DWORD WINAPI ThreadFunc(LPVOID val) 
{	
	ThreadContainer* tCnt = (ThreadContainer*)val;

	for(int i=tCnt->from; i<tCnt->to; i++)
	{
		cout << "Thread: " << tCnt->ThreadID << " numBaer: " << i << endl;
	}
	return 1;
};

int main(int argc, char* argv[])
{
	ThreadContainer tCnts;
	HANDLE					handles;

	tCnts.from	= 0;
	tCnts.to		= 10;

	LPVOID ptr	= (LPVOID)(&tCnts);
	handles			= CreateThread(NULL, 0, ThreadFunc, ptr, 0, tCnts.ThreadID);

	WaitForSingleObject(handles, INFINITE);

	return 0;
}

Schonmal danke für Hinweise. Ein einfacher Link zu gutem Beispielcode hilft mir auch schon! :)

MfG
 
Wenn die Erstellung des Threads länger dauert als die Berechnung selbst, dann würde ich garkein Multithreading verwenden.
 
Wenn deine Threads durchgehend rechnen, dann ist es eher kontraproduktiv mehr Threads als Rechenkerne einzusetzen, da das Betriebssystem ständig dazwischen umschalten muss. Zudem ist es schwieriger den Cache verfünftig zu nutzen.

Sofern alle Threads rechnen, ist es geschickter so viele Threads zu starten wie Prozessorkerne vorhanden sind und dann die zu berechnenden Daten entsprechend aufzuteilen.

Da du mit C++ arbeitest, kannst du dir ja auch mal OpenMP ansehen. Damit ist es relativ leicht Abschnitte zu parallelisieren.
 
Mein Frage ist daher, wie ich einen Thread "einschläfern" kann und wieder wecken wenn ich ihn brauche?!?!
Eine solche Prozesssynchronisation benutzt Du bereits:
WaitForSingleObject blockiert den aufrufenden Thread solange bis das Objekt signalisiert wird (Mutex, Semaphore, Thread, Prozesshandle, andere Handles, etc.).

Weitere Methoden, die Rechenzeit des aufrufenden Thread abgeben:
- Sleep/SleepEx
- WaitForMultipleObjects
 
Hallo Leute,

schonmal danke für eure Hinweise! Mein Programm läuft...allerdnigs ist es mehr Glück als Verstand denn die Synchronisation klappt garnicht wie ich gerade merke. :/ Daher mal eine einfaches Ding:

Code:
HANDLE mutex = CreateMutex(0, 0, 0);

cout <<  WaitForSingleObject(mutex, INFINITE);
cout << ReleaseMutex(mutex);

cout << WaitForSingleObject(mutex, INFINITE);

Sleep(1000);

cout << WaitForSingleObject(mutex, INFINITE);

return 0;

So wie ich WaitForSingleObject verstanden habe hält das Prog bis das Mutex wieder frei gegeben ist. In diesem Falle sollte es niemals frei werden was, wie ich dachte zu einem Deadlock führt. Das passiert aber nicht...hier wartet nichts auf niemanden. :freak:

Edit:

Ok...hat sich erledigt. In solchen Fällen wartet das System mit Absicht nicht zur Vermeidung von Deadlocks. :)
Ergänzung ()

Hmm... ich komme noch immer nicht weiter. Ich habe mein Schema mal in ein einfaches Programm verfrachtet. Wie gesagt...in diesem Falle wartet der Hauptthread leider nicht. Die COUTs werden aber alle abgearbeitet.

Code:
#include <iostream>
#include <windows.h>

using namespace std;

struct container
{
	HANDLE	mutex;
	bool		work;
	bool		kill;
};

DWORD WINAPI runThreadFunc(LPVOID val)
{
	cout << "START THREAD" << endl;
	container* c = (container*)val;
	while(!c->kill)
	{
		if(c->work)
		{
			cout << "WORK" << endl;
			Sleep(10000);	
			ReleaseMutex(c->mutex);
		}
		Sleep(5);	//IDLE
	}
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE	thread;
	DWORD		ID;

	container* c;

	c->kill		= false;
	c->mutex	= CreateMutex(0, 0, 0);
	c->work		= false;

	thread = CreateThread(NULL, 0, runThreadFunc, (LPVOID)c, 0, &ID);

	WaitForSingleObject(c->mutex, INFINITE);

	c->work = true;

	Sleep(50);

	cout << "WAIT FOR THREAD" << endl;

	WaitForSingleObject(c->mutex, INFINITE);

	return 0;
}

Bin für jeden Hinweis dankbar! ;)
 
Zuletzt bearbeitet:
Kannst du nochmal kurz ergänzen, was für ein Verhalten du dir erhoffst und was tatsächlich passiert? Und evtl, was dich daran wundert?
 
So wie ich das sehe, wartest Du im Mutex-freigebenden Thread auf einen Variable, die erst NACH der Freigabe des Mutexes gesetzt wird.
 
Was ich mir davon erhoffe ist, dass ich "von Außen" Einfluss auf den Thread habe. Er sollte rechnen wenn Arbeit da ist und trödeln wenn keine da ist. Um zu signalisieren ob er fertig ist soll er den/das(?) Mutex frei geben, was ich (so der Plan) einfach mit einem WaitForSingleObject vom Hauptthread aus prüfen kann. Allerdings geht das nicht, da nicht auf die Freigabe gewartet wird!
 
Ein Mutex dient, wie der Name schon sagt, hauptsächlich zum gegenseitigen Ausschluss. Das heißt, nachdem ein Thread WaitForSingleObject ausgeführt hat blockieren alle anderen Threads die ebenfalls auf dieses Mutex warten, und zwar bis der erste Thread dieses Mutex mittels ReleaseMutex wieder freigibt. Dein Ansatz kann also so schon prinzipiell nicht funktionieren, außerdem verwendest du ReleaseMutex auch noch falsch (das darf nur der Thread ausführen, der zuvor das WaitForSingleObject gemacht hat).

Dein Problem kann man zwar auch mit (mehreren) Mutexen lösen, aber was du eigentlich verwenden willst ist eine Semaphore (das ist der Klassiker), eine Condition Variable (gibt es erst ab Vista) oder ein Event (die meistens die Anzahl deiner Probleme eher erhöhen als verringern).
 
Raechaer schrieb:
..., außerdem verwendest du ReleaseMutex auch noch falsch (das darf nur der Thread ausführen, der zuvor das WaitForSingleObject gemacht hat).

Das ist so NICHT korrekt. Jeder Thread, der Zugriff auf das Mutex-Handle hat, darf das Mutex releasen. Wenn ein Thread via WaitXxx... blockiert und auf ein Mutex wartet, muss es ein anderer Thread aufheben oder das WaitXxx... muss ein finites Timeout haben, damit die Funktion auch ohne ein "signaled object" verlassen wird.

Ein Thread kann nicht gleichzeitig das Mutex releasen, während es gerade darauf mit WaitXxx... wartet.
 
Aus der MSDN:
The ReleaseMutex function fails if the calling thread does not own the mutex object.

Es ist sehr wohl so wie ich gesagt habe: nur der Thread, der sich das Mutex mit einem Wait geholt hat darf es später mit Release wieder freigeben.
 
XunnD schrieb:
Das ist so NICHT korrekt. Jeder Thread, der Zugriff auf das Mutex-Handle hat, darf das Mutex releasen. Wenn ein Thread via WaitXxx... blockiert und auf ein Mutex wartet, muss es ein anderer Thread aufheben oder das WaitXxx... muss ein finites Timeout haben, damit die Funktion auch ohne ein "signaled object" verlassen wird.

Ein Thread kann nicht gleichzeitig das Mutex releasen, während es gerade darauf mit WaitXxx... wartet.
Mh...also ich habe mir erst gestern noch ein Kapitel zu Thread durchgelesen(Tanenbaum: Moderne Betriebssysteme[3. Auflage 2009]) und wenn ich das richtig verstanden habe kann nur der Thread Mutex aufheben, der es auch gesetzt hat.
Den wäre ziemlich seltsam, das jeder Thread es auf heben könnte, so es doch grade dann gesetzt wird, wenn ein Thread in einen kritischen Bereich Eintritt. Soll bedeuten wenn ein Thread z.B. etwas auf einen Stack schreiben möchte, und deshalb den Mutex gesetzt hat, wäre es ziemlich ungeschickt, wenn nun ein anderer Thread auch auf den Stack schreiben möchte bevor der andere seine Aktion abgeschlossen hat, den wenn dieser den Mutex aufheben könnte, könnte es zu den gleichen Fehlern kommen, welche auch ohne Mutex auftreten.

Durch den Mutex wird das eintreten eines Threads in einen Kritischen Bereich gekennzeichnet und nur der Thread der ihn gesetzt hat das ihn wieder aufheben.
 
Zuletzt bearbeitet:
Wie peinlich für mich - ich hab die ganze Zeit Mutex und Event gleich gesetzt.
Events können von jedem Thread gesetzt werden (via SetEvent). Mutexe können - wie Ihr richtig bemerkt habt - nur durch den Thread released werden, der das Mutex besessen hat.


Wer mit Mutexe nur Prozess-lokale Objekt-Zugriffe synchronisieren will, kann sich ja noch Critical Sections anschauen.
 
Aha....so läuft der Hase. :)

Danke für die Diskussion Leute! Mein Thread-Pool läuft mitlerweile...allerdings realisiert über Boost und scoped_locks. :)

MfG
 
scoped_lock - klingt nach klassenbasierter critical section :)
 
Zurück
Oben