Mutex: kleines Beispielprogramm
-
Hallo Leute,
ich habe nun angefangen mich mit Mutex´s zu befassen
und versucht eine erste kleine Beispielanwendung mit Hilfe der
WinApi-Funktionen zu schreiben.
Ich bin mir jedoch nicht sicher ob ich das so richtig handhabe.
Hier ist mein erstes Programm dazu, in dem zwei Threads auf
eine Zählvariable zugreifen und diese abwechselnd in bestimmten Zeitabständen
bis 100 inkrementieren.// mutex03_wm.cpp : Definiert den Einsprungpunkt für die Konsolenanwendung. // #include "stdafx.h" #include <iostream.h> #include <windows.h> int c=0; int timestep = 50; int aim = 100; HANDLE hMutex; bool flag1,flag2; DWORD WINAPI ThreadProc1( LPVOID pvoid ) { while(c<=aim) { flag1=false; if(!WaitForSingleObject(hMutex, INFINITE)) { hMutex = CreateMutex(NULL, FALSE, "Mutex1"); flag1=true; } if(flag1) { cout <<"T1 : " << c <<endl; c++; ReleaseMutex (hMutex); } Sleep(timestep); } return NULL; } DWORD WINAPI ThreadProc2( LPVOID pvoid ) { while(c<=aim) { flag2=false; if(!WaitForSingleObject(hMutex, INFINITE)) { hMutex = CreateMutex(NULL, FALSE, "Mutex1"); flag2=true; } if(flag2) { cout <<"T2 : " << c <<endl; c++; ReleaseMutex (hMutex); } Sleep(200); } return NULL; } //------MAIN------// void main() { static HANDLE hThread1; DWORD dwThreadParam1 = 1; DWORD dwThreadID1; static HANDLE hThread2; DWORD dwThreadParam2 = 2; DWORD dwThreadID2; hMutex = CreateMutex(NULL, FALSE, "Mutex1"); cout << "Thread1 startet..."<<endl; hThread1 = CreateThread (NULL,0,ThreadProc1,&dwThreadParam1,0,&dwThreadID1); cout << "Thread2 startet..."<<endl; hThread2 = CreateThread (NULL,0,ThreadProc2,&dwThreadParam2,0,&dwThreadID2); cin.get(); TerminateThread (hThread1, 0); TerminateThread (hThread2, 0); }
Das Programm funktioniert, aber ich glaube man
kann das sehr viel eleganter lösen.
Wenn ja, wie ?Vielen Dank im Voraus.
grüße rom4o
-
Das Programm funktioniert, aber ich glaube man
kann das sehr viel eleganter lösen.
Wenn ja, wie ?Deine Thread-Funktionen sind beinahe gleich, da kann man eine draus machen. Das Geraffel mit den Flags und Mutexen finde ich merkwürdig. Ich kenn's so: Du hast einen Mutex, der wird einmal erstellt und nach dem ganzen Synchro wieder gelöscht. So, während den parallelen Abläufen "lockst" du dir den Mutex, wenn du alleinigen Zugriff auf Variablen haben willst und "unlockst" ihn direkt danach.
Es ließe sich z.B. so lösen:
#include <iostream> #include <windows.h> using namespace std; int c=0; int timestep = 50; int aim = 10; HANDLE mutex = CreateMutex( NULL, FALSE, NULL ); DWORD WINAPI ThreadProc( LPVOID pvoid ) { // Übergebenen int-Parameter holen int* pid = (int*)pvoid; int id = *pid; // Deine Schleife while(c<=aim) { // Mutex-Zugriff holen if ( WaitForSingleObject( mutex, INFINITE ) == WAIT_OBJECT_0 ) { // "c" erhöhen cout <<"T" << id << " : " << c <<endl; c++; // Mutex wieder freigeben ReleaseMutex( mutex ); } // Warten Sleep(timestep); } return 0; } void main() { // Threads erzeugen cout << "Thread1 startet..."<<endl; DWORD dwThreadParam1 = 1; HANDLE hThread1 = CreateThread (NULL,0,ThreadProc,&dwThreadParam1,0,NULL); cout << "Thread2 startet..."<<endl; DWORD dwThreadParam2 = 2; HANDLE hThread2 = CreateThread (NULL,0,ThreadProc,&dwThreadParam2,0,NULL); // Auf Threads warten WaitForSingleObject( hThread1, INFINITE ); WaitForSingleObject( hThread2, INFINITE ); // Thread-Handles schließen CloseHandle( hThread1 ); CloseHandle( hThread2 ); // Mutex zerstören CloseHandle( mutex ); }
Da der Hauptthread aber hier sowieso nur auf die beiden erzeugten Threads wartet, spricht nichts dagegen, nur einen extra Thread anzulegen:
void main() { // Thread erzeugen cout << "Thread startet..."<<endl; DWORD dwThreadParam1 = 1; HANDLE hThread1 = CreateThread (NULL,0,ThreadProc,&dwThreadParam1,0,NULL); // Hauptthread macht mit beim Hochzählen cout << "Haupthread mischt mit..."<<endl; DWORD dwThreadParam2 = 2; ThreadProc( &dwThreadParam2 ); // Auf Thread warten WaitForSingleObject( hThread1, INFINITE ); // Thread-Handles schließen CloseHandle( hThread1 ); // Mutex zerstören CloseHandle( mutex ); }
-
Hallo Badestrand, vielen Dank für die Hilfe.
Das hat sehr geholfen, das sieht viel strukturierter und auch logischer aus.
Da habe ich das ja total falsch gemacht.
Ich befasse mich ja parallel in einem anderen Thread mit dem Thema Parallelisierung.
Link: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1648817.html#1648817
Ich habe nun deinen Code genommen um Primzahlen in zwei Threads zu berechnen.
Bin nun jedoch wieder auf ein Problem gestoßen.
Wenn es dich interessiert dann folge einfach dem Link.viele grüße rom4o
-
Mutex-Objekte sind für Prozesse gedacht. Für Threads gibt es andere Dinge.
-
oh man kann irgendwer endlich mal diesen klappspaten aus dem forum verbannen? wie lange soll der hier noch rumtrollen?
-
Wen meinst Du mit rumtrollen? Den berniebutt?
Was er geschrieben hat ist vom Prinzip her vollkommen richtig.
Er meinte, daß ein Mutex innerhalb der Threads (also innerhalb EINES Prozesses) ein wenig oversized ist.Ein Mutex ist in erster Linie dazu da, über mehrere Prozesse (also z.B. Applikationen) hinweg zu synchronisieren.
Innerhalb einer Applikationen reicht für die Synchronisation zwischen den Threads z.B. die Critical Sections aus.
Critical Sections ist wesentlich schlanker und ressourcenschonender als Mutex.
Siehe auch: http://www.c-plusplus.net/forum/viewtopic-var-t-is-186523-and-highlight-is-.html
Martin
-
guck dir bitte berniebutt beiträge an, dann weisste was ich meine.
-
ascda schrieb:
guck dir bitte berniebutt beiträge an, dann weisste was ich meine.
Wo ist Dein Problem, Unreg?
-
@Mmacher: Danke für die Erklärung,
Ein Mutex ist in erster Linie dazu da, über mehrere Prozesse (also z.B. Applikationen) hinweg zu synchronisieren.
heißt das, dass man mit Critical Section zwischen Prozessen nicht synchronisieren kann?
Fällt dir ein Grenzbeispiel ein, ab dem Critical Section nicht mehr funktioniert und man auf ein Mutex zurückgreifen muss?
Sonst würde ich ja nun, wie ich erfahren habe, immer wenn es geht Critical Section nehmen, da dies viel schneller läuft.grüße rom4o
-
ascda schrieb:
oh man kann irgendwer endlich mal diesen klappspaten aus dem forum verbannen? wie lange soll der hier noch rumtrollen?
Hahaha,
ich hatte den genau gleichen GedankenMutex nur für Prozesse ... lach !
-
rom4o schrieb:
@Mmacher: Danke für die Erklärung,
Ein Mutex ist in erster Linie dazu da, über mehrere Prozesse (also z.B. Applikationen) hinweg zu synchronisieren.
heißt das, dass man mit Critical Section zwischen Prozessen nicht synchronisieren kann?
Fällt dir ein Grenzbeispiel ein, ab dem Critical Section nicht mehr funktioniert und man auf ein Mutex zurückgreifen muss?
Sonst würde ich ja nun, wie ich erfahren habe, immer wenn es geht Critical Section nehmen, da dies viel schneller läuft.grüße rom4o
Critical Section meint: Solange ein Thread dieses in Anspruch nimmt, wird das Task - Switching angehalten. Ein Mutex riegelt eine Funktion ab einer Waitroutine (WaitForSingleObject etc.) ab. Mutex regelt auch das Taskswitching nicht, sondern nur die Folge der Threads. Critical Section wirkt sofort bei EnterCriticalSection.
Einem Thread kann sehr wohl innerhalb einer Mutex gesicherten Funktion Rechnerzeit abhanden kommen. Genau dafür aber - damit das nicht passiert gibt es die Critical Section. Die hat nichts mit den Threads zu tun, sondern mit dem Taskscheduler. Es sichert einen Thread einfach ab, bis es diese Bereiche, wo es kritisch werden kann abgegessen hat ...
An und für sich ist das nicht schwer - es ist nur schwer zu beschreiben, in parallelen Zyklen.
Für das Grundverständnis von Prozess, Threads und dem Mulitasking empfehle ich immer das Buch: PC Intern von Data Becker.
Darin sind auch schöne Beispiele, wie diese Begriffe von Threadsynchronisation, die da sind: Mutex, Semaphore, Critical Sections, Event und andere schöne Objekte, greifen.
-
rom4o schrieb:
heißt das, dass man mit Critical Section zwischen Prozessen nicht synchronisieren kann?
Genau so ist es.
rom4o schrieb:
Fällt dir ein Grenzbeispiel ein, ab dem Critical Section nicht mehr funktioniert und man auf ein Mutex zurückgreifen muss?
Einen Mutex statt eines Critical Sections muß man dann nehmen, wenn man z.B. dafür sorgen möchte, daß die gleiche Applikation nur einmal zur gleichen Zeit gestartet werden darf. D.h. Ein Benutzer startet die gleiche Applikation (oder auch eine Kopie an einem anderen Pfad) nochmal, und über den Mutex weiß dann die zweite Applikation, daß er bereits schon von der ersten Applikation angelegt wurde. -> also ist hier eine Synchronisierung über Prozeßgrenzen hinweg nötig und damit ein Mutex (oder auch alternativ eine Semaphore).
Warum z.B. ein Mutex ressourcenfressender ist als Critical Section, liegt u.a. hauptsächlich daran, daß Mutexe sog. Kernel-Objekte sind (also salopp ausgedrückt, sehr tief im System verankert sind und deshalb mehr Prozessorzeit im Scheduler beansprucht), die Critical Sections dagegen "nur" User-Objekte sind.
Das alles (Mutexe, Semaphoren, Critical Sections, ...) ist ein eigenes Kapitel für sich, d.h. eine ordentliche Einarbeitung in dieses Thema ist sehr empfehlenswert (Buch oder Tutorials, siehe Links in meinem ersten Posting hier).
Alleine schon, daß Du mit dem Mutex Deine ersten "Gehversuche" erfolgreich unternommen hast ist schon mal ein sehr guter Schritt!Martin
-
Nachtrag:
Ein recht einfach gehaltenes Tutorial (in deutsch!) möchte ich hier nicht vorenthalten:
http://www.jliforum.de/board/viewtopic.php?p=63665#63665Martin
-
Hallo Leute, danke für die Erklärungen,
hat sehr geholfen.
@Mmacher: Das Tutorial war sehr gut,
jetzt kenne ich mich auch mit Event und Semaphore aus.bb rom4o
-
CStern schrieb:
Mutex nur für Prozesse ... lach !
NIEMAND hat hier gesagt, Mutex-Objekte seien ALLEIN für Prozesse einsetzbar. Wie hier mehfach ausgeführt worden ist, gelten sie global im System und können somit auch nur in EINEM Prozess genutzt werden. Es fragt sich aber, warum soll man tun, wenn es speziell dafür Critical-Section-Objekte "SDK: ... slightly faster, more efficient ..." gibt.
Jeder kann seine Oma vom Flughafen auch mit dem LKW oder dem Moped abholen. Die Oma wird wahrscheinlich sagen: "Mein lieber Junge (mein liebes Mädchen), der Bus oder ein Taxi hätte es doch viel bequemer getan. Wir gehen jetzt erst einmal gemeinsam Kaffee trinken". Windows und die WinApi sind nicht so feinfühlig und können das auch nicht sein.
Rom4o: Du bist auf dem richtigen Weg bei einem komplexen Thema. Sobald für eine Synchronisation mehrere Prozesse (Applikationen) beteiligt sind, braucht man Mutex. Critical Section geht nur innerhalb eines Prozesses. Du brauchst zum Programmieren nicht den Rat der Oma!