Seite 3 von 5

Re: Und nun ein C++-Problem...

Verfasst: 29.01.2010 11:58
von P7BB
Hi,

ok, das parallel laufen hatte ich ja schon gesagt. Ich würde es bevorzugen, dass ich aber nicht sage:
Programm 1: 1-1.000.000
Programm 2: 1.000.001-2.000.000
Programm 3: 2.000.001-3.000.000
Programm 4: 3.000.001-4.000.000

Sondern ich würde es lieber so regeln:
Hauptprogramm startet primzahl-programme folgendermaßen: prim.exe [start] [anzahl] [anzahl gestarteter programme]
Das Programm verarbeitet das so:
Es fäng bei [start] an nach Primzahlen zu suchen, und zwar bis es [anzahl] erreicht hat. Danach wird [anzahl] mit [anzahl gestarteter programme] multipliziert, um den neuen start rauszufinden und danach geht es immer so weiter ;)

So können die einzelnden Primzahl-Programme dann fortlaufend weiterrechnen, ohne dass ich ein limit oder ähnliches festlege ;)
Falls du noch einen Verbesserungsvorschlag zu der Methode hast, sag mir bescheid, weil dann würd ich mir ne Menge Arbeit sparen ;)

Achja: Meinst du, dass ich auf einem 4-Kern-Prozessor auch 4 Programme starten kann, ohne das Windows komplett unansprechbar wird? (Win Vista Home Premium // Intel Core 2 Quad 2,33 GHz)
Ansonsten werd ich nämlich dann nur 3 Programme immer starten ;)

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 12:15
von gn#36
Da Windows ein Multitasking System ist (und zwar unabhängig davon wie viele Prozessorkerne du nun genau hast) kann es durchaus auch noch weitere Programme verarbeiten während du es mit 4 Prozessen auslastest. Allerdings kannst du dich denke ich auf gewisse Geschwindigkeitseinbußen einstellen wenn du alle Kerne auf 100% jagst mit deinem Programm, die Prozesse werden zwar immer wieder für andere Prozesse unterbrochen, aber ob das immer zu den Zeiten passiert die für deine anderen Aktivitäten sinnvoll sind ist die Frage. Parallel noch Filme schauen dürftest du nicht können, dafür solltest du dir einen Kern aufsparen.

Was den Programmaufruf angeht: Mein Skript ist eine Art "Wrapper" für das Programm das dir die Aufteilung abnimmt. Du rufst nur das Skript auf und es startet dann im Hintergrund das Programm. Diese Art von Parallelisierung ist deutlich einfacher als wenn du das direkt ins Programm einbaust. Wenn du es unbedingt im Programm drin haben willst, dann musst du dich da genauer einlesen, wie ich schon sagte, mal eben so nebenbei erklärt ist das nicht. Das geht auch je nach Betriebssystem anders, unter Linux kannst du aus einem Programm ganz einfach zwei machen mit Hilfe des Befehls fork. Der folgende Code wird von beiden Programmen ausgeführt und du kannst anhand des Rückgabewertes entscheiden welcher Prozess der erste und welcher der zweite ist. Falls es sowas unter Windows auch gibt ist es natürlich ganz einfach das ganze aufzuteilen:

Code: Alles auswählen

... init und so

int prozesszahl = 4;
startwert = 1;
endwert = atoi(argv[1]);
schrittgroesse = endwert/prozesszahl;
// 4 Kindsprozesse erzeugen
for(int prozesscounter = 0; prozesscounter < prozesszahl; prozesscounter++)
{
	if(0 == (pid = fork()))
	{
		//Kindsprozess
		startwert = schrittgroesse * prozesscounter + 1;
		endwert = schrittgroesse * (prozesscounter + 1);
		//Das Kind soll keine weiteren Prozesse erzeugen:
		break;
	}
}
if(pid == 0)
{
//Kindsprozesse
//Hier die Berechnungen mit den oben bestimmten start und Endwerten durchfuehren.
//Die pid oder die prozessnummer sollte in den Dateinamen verwendet werden um die daten hinterher zusammenfuegen zu koennen.
//Auch der Teil ist nicht unbedingt immer einfach zu erledigen.
//Eventuell machst du das auch mit Pipes o.ae.
}
else
{
//Elternprozess
//Hier muss auf die Kindsprozesse gewartet werden, danach werden die Ergebnisse zusammengefasst und in die Datei geschrieben/ausgegeben.
}
Naja wie schon gesagt, wenn du das gleiche in Windows machen willst musst du dir was zum lesen suchen, da kenne ich mich nicht so aus mit Multithreading oder IPC.

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 13:21
von P7BB
Hi,

danke :) Das wäre Variante 1 von meinem Programm. Variante 2 hat aber kein Limit, also zählt praktisch endlos weiter. Deshalb wäre bei Variante 2 ein Limit nicht so praktisch, denk ich... Aber das kann ich relativ gut umbauen, denk ich. ;)

Ich habs gestern abend nochmal ausprobiert, mit den Programmen... Also ich konnte 8 Programme problemlos starten und nebenbei surfen (aber acht mal dieselben zahlenbereiche...). Mit mehr Programmen hab ichs nicht mehr ausprobiert... Aber ich denke 8 ist schon ok :D

Aber eine frage... was macht "fork()"?

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 14:06
von gn#36
In Windows: Vermutlich nichts, es sei denn du hast eine entsprechende Bibliothek. In Unix dupliziert es das aktuell laufende Programm, aus eins mach zwei sozusagen. Beide laufen ab genau der Stelle weiter wo das Fork steht, nur der Rückgabewert unterscheidet sich, der Vaterprozess bekommt immer eine Prozess ID des Kindes, der Kindsprozess immer eine 0.

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 14:14
von P7BB
Ok, aber wenn in Windows nichts passiert würde das doch bei mir dann nicht funktionieren, oder seh ich das jetzt falsch?

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 15:03
von gn#36
Liest du eigentlich meine Posts oder schaust du dir nur den Code an? Ich habe doch direkt im ersten Post in dem fork vorkam geschrieben dass das unter Linux funktioniert. Das bash Skript kriegst du mit Cygwin auch unter Windows zum laufen denke ich, vielleicht den C Code auch.

Es kann sehr gut sein dass es Portierungen gibt die fork auch unter Windows ermöglichen, aber es kann genau so gut sein dass du dir da andere Mechanismen suchen musst, in jedem Fall wäre eine fork() Implementierung in Windows vermutlich nicht sonderlich effektiv, da etwas andere Grundannahmen über Prozesse gemacht werden als in Unix. Benutz' eine Suchmaschine deiner Wahl, vermutlich ist das starten eines unabhängigen Prozesses in Windows auch nicht sehr schwierig. MSDN sagt zu Prozessen z.b. das hier: http://msdn.microsoft.com/en-us/library ... S.85).aspx

Die Alternative zu separaten Prozessen ist die Verwendung von separaten Threads. Da gibt es Bibliotheken die es in beiden Systemen gibt, z.b. den POSIX Standard pthreads: http://sourceware.org/pthreads-win32/ Du kannst natürlich auch die Win32 Api dafür nutzen, ich finde die POSIX Variante aber übersichtlicher (was vermutlich reine Gewöhnungssache ist).

Mit Threads umzugehen ist aber ein bisschen schwieriger als mit Prozessen, weil alles immer noch innerhalb des gleichen Adressraums abläuft, d.h. Änderungen in einem Thread haben wenn du nicht aufpasst Änderungen in anderen Threads zur Folge, diese Fehler zu finden ist nicht immer einfach. Bei einem separaten Prozess kann dir das so nicht passieren.

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 15:53
von P7BB
gn#36 hat geschrieben:Liest du eigentlich meine Posts oder schaust du dir nur den Code an? Ich habe doch direkt im ersten Post in dem fork vorkam geschrieben dass das unter Linux funktioniert. Das bash Skript kriegst du mit Cygwin auch unter Windows zum laufen denke ich, vielleicht den C Code auch.
Ich les mir deine Beiträge durch, nur es ist etwas schwierig, den Überblick zu behalten, da viele Sachen, die du postest, für mich neu sind.
Das Bash-Script ähnelt ja ziemlich stark einer Batch.. oder ist das das gleiche? o.O Zumindest ist die Funktoinsweise von Batch-Dateien und Bash-Dateien wohl recht gleich, wenn ich das richtig aus deinem Code rauslesen konnte...

Das mit den Threads kann ich mir noch nicht so richtig vorstellen, wie das abläuft. Also es könnte dort beispielsweise passieren, dass eine variable einen wert bekommt und dieser wert beinflusst dann unabsichtlich andere threads?

Aber ich denke mal, dass ich das mit Prozessen dann realisieren werde, zumal du ja auch sagtest, dass Threads etwas schwieriger sind. ;)
Ich werd später, wenn ich etwas mehr Zeit hab, nochmal gucken, ob ich das mit Prozessen soweit verstanden hab. Ich melde mich dann hier nochmal ;)

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 16:31
von gn#36
P7BB hat geschrieben:Das Bash-Script ähnelt ja ziemlich stark einer Batch.. oder ist das das gleiche? o.O Zumindest ist die Funktoinsweise von Batch-Dateien und Bash-Dateien wohl recht gleich, wenn ich das richtig aus deinem Code rauslesen konnte...
Im Prinzip schon. Bash ist einfach nur die Shell die das ganze ausführt, so ähnlich wie php der Interpreter für php Skripte ist gibt es eben eine Syntax für bash Skripte und noch viele weitere Shells. Bash ist meist die Standardshell unter Linux, es gibt mit beispielsweise Cygwin aber auch Windowsversionen davon.
Das mit den Threads kann ich mir noch nicht so richtig vorstellen, wie das abläuft. Also es könnte dort beispielsweise passieren, dass eine variable einen wert bekommt und dieser wert beinflusst dann unabsichtlich andere threads?
Ja genau das kann passieren. Einfaches Beispiel:

Code: Alles auswählen

//Globale Variable:
int id = 100;
//...
//Thread 1:
while(id <= 200)
{
	printf("Ich bin die Geburt.");
	id++;
}

//....
//Thread 2:
while(id >= 10)
{
	printf("Ich bin der Tod.");
	id--;
}
Abgesehen davon dass dieser Code natürlich völliger Schwachsinn ist ist hier das Ergebnis dem Zufall überlassen, zumindest wenn man annimmt dass einer der beiden Threads lange genug läuft um seine Abbruchbedingung erfüllen zu können. Welcher von beiden "gewinnt" kann man nicht sagen. Wenn man Pech hat gibt das auch einen Deadlock weil immer wenn der eine Thread gerade fast soweit wäre dass er die Schleife verlassen kann der andere Thread eingreift und die Variable wieder in die andere Richtung drückt. Vielleicht laufen auch einfach beide gleichzeitig und ändern die Variable abwechselnd, wenn die Variable komplexer ist und die Änderungsoperation nicht atomar abläuft (d.h. die komplette Änderung wird grundsätzlich nicht unterbrechbar durchgeführt), dann kannst du sogar Mischwerte aus beiden Änderungen in der Variable stehen haben die weder dem von Thread 1 noch dem von Thread 2 gewollten Wert entsprechen.

Bei Prozessen kann dir das so nicht passieren weil die Prozesse nicht auf die gleichen Speicherbereiche zugreifen können. Natürlich kann man auch hier auf Synchronisationsprobleme stoßen, aber man muss sich zumindest keine Gedanken mehr über Threadsichere Programmierung machen.

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 17:54
von P7BB
Okay, dann kann ich mir das jetzt besser vorstellen.
Ich hab übrigens gerade ein multithreading-beispiel im internet gefunden:

Code: Alles auswählen

#include <string>
#include <iostream>
#include <windows.h>

using namespace std;

long WINAPI thread1()
{
        for(int i = 0; i < 10; i++)
        {
                cout << "Thread1" << endl;
                Sleep(100);
        }

        return 0;
}

long WINAPI thread2()
{
        for(int i = 0; i < 10; i++)
        {
                cout << "Thread2" << endl;
                Sleep(100);
        }

        return 0;
}

int main(int argc, char **argv)
{
        HANDLE hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread1, 0, 0, 0);
        HANDLE hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread2, 0, 0, 0);

        WaitForSingleObject(hThread1, INFINITE);
        WaitForSingleObject(hThread2, INFINITE);

        CloseHandle(hThread1);
        CloseHandle(hThread2);

        return 0;
}
Meine Frage wäre, ob es theoretisch möglich wäre, dass nicht
Thread1
Thread2
Thread1
Thread2
...
rauskommt, sondern wenn ein Kern mehr ausgelastet ist, dass dann
Thread1
Thread1
Thread2
Thread1
Thread1
Thread2
...
rauskommt. Oder wird das ganze automatisch synchronisiert?
Achja:
(int) i wird ja erst während des threads erstellt, also wäre in dem fall doch die variable "privat" und nicht global, oder?

Edit: Ich will Multithreading jetzt gar nicht großartig weiter durchgehen, aber die Fragen schwirren mir noch im Kopf rum... ;)

Re: Und nun ein C++-Problem...

Verfasst: 30.01.2010 18:24
von gn#36
Wenn die Pausen da nicht so lang angesetzt wären (bzw. du dir die Pausen ganz sparen würdest) dann würde da vermutlich keine abwechselnde Ausgabe mehr herauskommen, jedenfalls nicht unbedingt, eine automatische Synchronisation findet nämlich eben genau nicht statt. In dem Beispiel kommen sich die beiden Threads auch nicht über die Variablen in die Quere, wenn du aber z.b. beide in die gleiche Datei schreiben lassen würdest dann würden sie sich mit Sicherheit in die Quere kommen (letztlich tun sie das ja schon indem sie beide auf den Bildschirm ausgeben, die Ausgaben des einen Threads werden immer wieder durch die des anderen unterbrochen).

Teilweise musst du auch bei Systemfunktionen aufpassen ob diese Thread-safe sind oder nicht. Auch wenn die meisten Funktionen die du so benutzt vermutlich sicher sein sollten sollte man sich nicht darauf verlassen. Zum Beispiel könnte eine Funktion mittels statischer Variablen Werte zwischenspeichern um diese schneller verfügbar zu haben. Für einen anderen Thread könnten diese zwischengespeicherten Werte aber vielleicht falsch sein.