C++ mit .NET Bernd Marquardt Microsoft Regional Director Germany Software & Consulting [email protected] http://www.go-sky.de Hinweis  Ja, es sind viele Slides…  …aber einige Slides sind nur der Vollständigkeit halber.

Download Report

Transcript C++ mit .NET Bernd Marquardt Microsoft Regional Director Germany Software & Consulting [email protected] http://www.go-sky.de Hinweis  Ja, es sind viele Slides…  …aber einige Slides sind nur der Vollständigkeit halber.

C++ mit .NET
Bernd Marquardt
Microsoft Regional Director Germany
Software & Consulting
[email protected]
http://www.go-sky.de
Hinweis

Ja, es sind viele Slides…

…aber einige Slides sind nur der
Vollständigkeit halber dabei und werden
im Vortrag selbst sehr schnell erledigt!

Wir werden nicht alle Demo‘s hier
testen…

…aber in einer „stillen Stunde“ können
Sie die Demo‘s selbst ausprobieren
Agenda




Einführung
C++ Managed Extensions für .NET
•
•
•
Stand der Dinge
Anwendung: Wrapper-Klassen
Performance
2003
C++ in Visual Studio 2005 (Whidbey)
•
•
•
CLI
Generische Typen, STL und …
OpenMP
Zusammenfassung
2005
Einführung

C und C++ sind wichtige
Programmiersprachen unter Windows
•
•


Bis 1992 in „reinem“ C und SDK
Danach mit C++ und MFC
Windows „begann“ mit C
•
VB kann erst später
Bei Microsoft wird auch heute noch
FAST alles mit C++ codiert
•
Das soll aber in Zukunft anders werden
Einführung


Vorteile von C++:
•
•
•
•
Performant
Volle Kontrolle, man kann alles machen
Wenig zu tippen
Es geht immer alles, was möglich ist
Nachteile von C++:
•
•
Schwer zu lernen
Viele Fallstricke und „Pumpen, vor die man
laufen kann“
Einführung

Die „Pumpen“ von C und C++
• Zeiger
• Makros – das „Klammerproblem“
• new / delete
• switch / break
• Globale Variablen und Funktionen
• Variablen-Initialisierung
• …
C++ und .NET: Heute



C++ Managed Extensions
•
Zugriff auf das .NET-Framework
Aufruf von unmanaged Code
Wrapper-Klassen
•
Wrappen von MFC-Klassen
C++ Man. Ext. für .NET

C++ Managed Extensions (VS 2002 und
2003):
•
•
•
•
•
•
Code sieht nicht sehr schön aus
Code ist schwer zu lesen
Unterscheidung von „managed“ und
„unmanaged“ Objekten ist schwierig
Die _-Taste geht sehr schnell kaputt 
Managed Extensions sind dem C++
„aufgedrückt“ worden
VS 2002: Kein Designer für Windows
Forms mit man. C++ enthalten
IL und nativer Code
void ManagedFunc() {}
#pragma unmanaged
void NativeFunc() {}
#pragma managed
void AnotherManagedFunc() {}
C:>CL.EXE /LD /clr cpptest.cpp
C:>ILDASM.EXE cpptest.dll
cpptest.cpp
IL und nativer Code
#pragma unmanaged
void NativeFunc()
{}
#pragma managed
void ManagedFunc()
{ NativeFunc(); }
Definition von .NET Typen
referenzierende
Typen
__gc class ManagedClass {};
__gc struct ManagedClass2 {};
__gc __interface ManagedInterface {};
__delegate void ManagedDelegate();
Wertetypen
__value class ManagedValueType {};
__value struct ManagedValueType2 {};
__value enum ManagedEnum {};
Referenzierende Typen




Instanzierung durch expliziten
__gc new Aufruf
Speicher wird auf dem "Managed
Heap" angelegt
Garbage Collector gibt Speicher für
Instanzen wieder frei
Variablen grundsätzlich Zeigertypen
(__gc*) oder Referenztypen (__gc&)
•
GC kontrolliert __gc* und __gc&
Wertetypen

Sind grundsätzlich immer in "etwas"
enthalten…
•
•
•

…als globale Variable in der
Anwendungsdomäne
…als lokale Variable im Stackframe
…als Feld eines Typs in einer Instanz
dieses Typs
Instanziierung und Lebenszeit an
enthaltende Entität gebunden
•
Die Lebenszeit also ist inkompatibel
zur Lebenszeit von .NET-Objekten
Schnittstellen
__gc __interface I1
{
void M1();
void M2();
};
__gc class ManagedClass : public
I1
{
public:
implizite Implementierung
void M1 {}
void I1::M2() {}
explizite Implementierung
};
Enumeratoren
// C++ Managed Extensions
[System::Flags]
__value public enum ManagedEnum : short
{
red
= 1 << 0, // 1
yellow = 1 << 1, // 2
blue
= 1 << 2 // 4
};
Delegates
public __delegate void ADelegate();
ADelegate* pD1 = new ADelegate(pRefToClassXInstance,
&ClassX::NonStaticMethod);
pD1->Invoke();
ADelegate* pD2 = new ADelegate(0,
&ClassX::StaticMethod);
pD2->Invoke();
Methoden
C++
using namespace System;
using namespace System::Runtime::InteropServices;
public
{
void
void
void
};
__gc __interface ITest
M1(Int32 n, String* ps);
M2(Int32* pn, String** ppstr);
M3([Out]Int32* pn, [Out] String** ppstr);
using Systen;
public
{
void
void
void
}
interface ITest
M1(Int32 n, String ps);
M2(ref Int32 pn, ref String ppstr);
M3(out Int32 pn, out Int32 ppstr);
C#
Eigenschaften
public __gc class Test
C++
{
int _age;
public:
__property int get_Age() { return _age; }
__property void set_Age(int age) { _age = age; }
}
pTest->Age = pTest->Age + 1;
public class Test
{
private int _age;
public int Age
{
get {return _age;}
set {_age = value;}
}
test.Age = test.Age + 1;
}
C#
Indexer
using namespace System;
using namespace System::Reflection;
C++
public __gc __interface INameList
{
__property String* get_Name(int i);
__property void set_Name(int i, String* psNewVal);
};
INameList* pNL = ...;
string str = pNL->Name[0];
using System;
public interface INameList
{
String this[int i] { get; set; }
}
INameList nl = ...;
string str = nl[0];
C#
Exception Handling


Syntax ist ähnlich wie im klassischen C++
Managed Exceptions sind Referenzen auf
beliebige .NET-Objekte
•

Verschiedene catch-Blöcke eines tryBlocks können sowohl C++-Exceptions als
auch .NET- Exceptions behandeln
•


Basisklasse System::Exception
C++-Exceptions müssen vor .NET-Exceptions
behandelt werden
Auslösen und Abfangen von C++ und .NETExceptions in einer try-Anweisung ist
zulässig
Win32 Structured Exception Handling (__try,
__except) ist in Managed Code unzulässig
Exceptions
void ManagedFunc(int i)
{
try
{
...
}
// C++ Exception
catch (int i)
{ System::Console::WriteLine(i); }
// nicht CLS kompatible .NET Exception
catch (System::Exception* pE)
{ System::Console::WriteLine(pE->Message); }
// CLS kompatible .NET Exception
catch (System::Object* pE)
{ System::Console::WriteLine(pE); }
__finally
{ ... Ressourcen hier freigeben ... }
}
Determin. Finalisierung

C++-Klassen werden als lokale
Variablen automatisch deterministisch
finalisiert
•
•

Der Destruktor wird beim Verlassen des
Scope aufgerufen…
…auch wenn der Scope durch eine
Exception verlassen wird
Instanzen von .NET Klassen werden
nicht automatisch deterministisch
finalisiert
•
Die deterministische Finalisierung muss
manuell durch try/__finally-Blöcke
realisiert werden
Determin. Finalisierung

In GC-Klasse kann ein Destruktor
implementiert werden
•
Überschreibt Object::Finalize und
implementiert Methode __dtor
• Finalize wird von Garbage Collector
aufgerufen, bevor Objekt zerstört wird
• __dtor wird vom delete-Operator
aufgerufen
• __dtor ruft zuerst
GC::SuppressFinalize und dann
Finalize auf
Aufruf von unman. Code



Es gibt sehr viel Code in C und C++
Vieles davon kann man weiter verwenden
Aufruf von unmanaged Code:
• [DllImportAttribute(…)] (geht mit allen
.NET-Sprachen)
•
•
•
Daten werden automatisch konvertiert
Achtung: Anwendung von Zeigern
„It just works“-Methode (geht nur mit C++)
•
•
Einfach die Header-Dateien einfügen und API‘s
aufrufen
Daten müssen konvertiert werden
C++ als .NET Sprache
 Vorteile
• Ermöglicht das Mischen von MSIL-Code und
nativem Code
• Aufruf nativer Funktionen im MSIL-Code ist:
…viel einfacher
…viel schneller
…ohne Einschränkungen möglich
 Nachteile
• „Kranke“ Syntax
Wrapper-Klassen





Managed Wrapper-Klassen
umhüllen eine normale unmanaged
C++-Klasse
Die Hüllklasse funktioniert wie ein
Proxy
Die Hüllklasse hat die gleiche
Funktionalität wie die C++-Klasse
Es wird immer ein „Klassenpaar“
erzeugt, bzw. zerstört
Beide Klassen können in einer Datei
angelegt werden
•
Einfache Verwaltung
Wrapper-Klassen


Ein Objekt der Wrapper-Klasse kann
unter .NET wie ein normales .NET-Objekt
benutzt werden
Die Daten-Konvertierung wird ggf. in der
Wrapper-Klasse implementiert
•
•
•
Byte, int, long, short, float, double keine
Konvertierung nötig
String muss konvertiert werden
•
Achtung: ANSI oder UNICODE beachten
Struct‘s müssen meistens angepasst werden
•
Es gibt dafür spezielle Attribute (z.B. FieldOffset)
Wrapper-Klassen
class CppClass {
public:
// Konstruktor
CppClass() {
…}
// Destruktor
~CppClass() {
…}
// Methoden
void native_f() {
…}
};
__gc class ManClass {
public:
// Konstruktor
ManClass() {
m_pC = new CppClass();
}
// Freigabe
~ManClass() {
delete m_pC;
}
// Methoden
void managed_f() {
m_pC->native_f();
}
private:
CppClass * m_pC;
};
Wrapper-Klassen





Erzeugung einer man. C++-Klasse
•
Data Member in der Wrapper-Klasse: Zeiger vom
Typ der C++-Klasse
In der managed Klasse müssen die
Konstruktoren nachgebildet werden
In der Dispose-Methode der managed Klasse
die Instanz der unmanaged Klasse zerstören
ACHTUNG: Wrapper-Objekt steht unter der
Kontrolle des Garbage Collectors
Alle public-Methoden der unmanaged
Klasse in der managed Klasse
implementieren
Wrapper-Klassen

Destruktoren
•
•
Sowohl den Destruktor als auch die
Dispose-Methode implementieren
•
Wrapper-Klasse von IDisposable ableiten
„Selbst-gesteuertes“ Zerstören des
Objektes durch Dispose-Aufruf
• Dort Finalize() aufrufen
• GC::Supress::Finalize wird automatisch
vor dem Finalize()-Aufruf getätigt
• Dispose-Aufruf vergessen: Garbage
Collector schlägt mit dem Destruktor zu
Probleme mit Wrappern






Variable Parameteranzahl
Daten-Marshaling
Default Argumente
Destruktoren (Garbage Collector)
Properties
Überladen von Operatoren
•
Wenn der Wrapper z.B. mit VB oder C#
genutzt werden soll, müssen die
überladenen Methoden auch als “echte”
Methode implementiert werden
•
•
C#: Operator-Overloading erlaubt
VB: nicht erlaubt
Wrapper-Klassen

Wrapper sind eine einfache Möglichkeit,
um existierende C++-Klassen weiter zu
benutzen
•


Innerhalb der unmanaged C++-Klassen ist
alles erlaubt (z.B.: Multiple Inheritance)
Wertet die C++-Klassen auf, da sie nun
aus allen .NET-Sprachen aufgerufen
werden können
Performance beachten
•
Kontext-Wechsel, Konvertierungen
MFC-Dialoge wrappen

Anwendung von Wrapper-Klassen

Frage:
Kann man von alten monolitischen
MFC-Applikationen irgendetwas weiter
verwenden (mit Hilfe von Wrappern)?

Analyse

In Dialogen steckt oft ähnlich viel Code
wie im Hauptfenster
•

Dialoge sind aufwändig zu erstellen
•
•

Ausnahme: Applikationen mit vielen
mathematischen Rechenalgorithmen
Platzierung der Controls (zeitaufwändig:
Design)
Programmierung (zeitaufwändig: Tests)
Es wäre gut, wenn man die Dialoge
weiter verwenden könnte  WrapperKlassen!!!
Der Migrationsweg (1)

Alle Dialoge in einer MFC-DLL ablegen
•
•
•
CPP- und H-Dateien ins DLL-Projekt
einfügen
Resource.h hinzufügen (kopieren)
RC-Datei aus Applikation mit Notepad
editieren
• Nur Dialoge übernehmen
• Drag&Drop in der IDE klappt (manchmal)
irgendwie nicht so ganz
Der Migrationsweg (2)

Für jeden Dialog eine Wrapper-Klasse
generieren
•
•
•


Automatische Erzeugung mit einem
kleinen Tool (ist möglich)
Unicode / ANSI auswählen
Wrapper kann auch von Hand erzeugt
werden
Manchmal muss die Typ-Konvertierung
„von Hand“ implementiert werden
„#pragma managed“ und „#pragma
unmanaged“ korrekt verwenden
Der Migrationsweg (3)

DLL Kompilieren
•
•

„Use managed extensions“ auf „YES“
setzen
MFC-Library STATISCH linken (WICHTIG)
Hauptfenster mit .NET erzeugen
•
•
•
•
Referenz auf DLL anlegen
Menü, Toolbar und Statuszeile (usw.)
implemetieren
Entsprechende Wrapper-Objekte aufrufen
Übersetzen und testen
Der Migrationsweg (4)

Deutliche Zeiteinsparung beim Umstieg
auf .NET
•
•

Kein Programmieren und Testen der
Dialoge
Kein Neu-Design der Dialoge (das kann
auch ein Nachteil sein!  Design)
Wrapper evtl. mit Tool generieren
Performance


Ein Hauptgrund für C und C++:
•
Performance
Auch unter .NET ist C++ sehr schnell
•
•
•
Im Moment: Die schnellste .NET-Sprache
Wichtig bei mathematischen
Berechnungen (Algorithmen)
Weniger wichtig bei User Interfaces,
mehrschichtigen Datenbank-Applikationen
•
Flaschenhals hier: Datenbank und/oder
Netzwerk
Arithmetik (einfach)

((double) i + (double) j) * 2.5


VB 6.0
VC++ 6.0

VC .NET unmng.
5.703 sek

VC .NET mng.
C#
VB .NET
7.235 sek
8.563 sek
9.250 sek


50.610 sek
5.860 sek
VS 6.0
Asm.
VS .NET
CLR
Arithmetik (kompliziert!)

(((double) i + (double) j) * 2.5) / (i + j + 1)


VB 6.0
VC++ 6.0
80.313 sek
24.891 sek

VC .NET unmng.
24.890 sek

VC .NET mng.
C#
VB .NET
24.850 sek
24.891 sek
24.990 sek


VS 6.0
Asm.
VS .NET
CLR
Arithmetik (esotherisch!)




Fast Fourier Transformation
•
•
Sägezahn aus 65.536 Einzelwerten
Daten-Array als lokale Variable
VC++ unmng. (lok. Array)
VC++ mng. (lok. Array)
63 msek
63 msek
Mathematische Algorithmen sind sehr
schnell – Rechnenoperationen ohne
Einschränkungen
Arithmetik (esotherisch!)




Fast Fourier Transformation
•
•
Sägezahn aus 1.048.576 Einzelwerten
Daten-Array auf dem Heap (mit VC.NET
unter Kontrolle des Garbage Collectors)
VC++ unmng. (nat. Heap) 2.250 sek
VC++ managed (GC)
2.609 sek
Auch mit GC sind (fast so) schnelle
Berechnungen möglich
String-Operationen

Anhängen von 100.000 Strings zu je 10
Zeichen (Unicode)

VB6, normaler String:
Einfacher MFC-String:
MFC-String mit Allokation:
C#, einfacher String:
C#, StringBuilder:
C++, char-Array, memcpy:





44.231 sek
17.340 sek
0.046 sek
87.820 sek
0.047 sek
0.010 sek
Aufruf von unman. API‘s
 Eine
herkömmliche Windows-DLL kann
von einer Applikation mit managed Code
aufgerufen werden
 Die Funktion erhält double-Wert und gibt
einen int-Wert zurück
 Die Funktion wird 10.000.000 mal
aufgerufen


aus VC++ 6.0
aus C#
1.500 sek
4.453 sek
Weitere Ergebnisse



Compilier-Geschwindigkeit des JITCompilers
Frage: Wieviel Zeit geht bei der
„Laufzeit-Übersetzung“ des IL-Codes
verloren?
JIT kompiliert ca. 5000 Zeilen IL-Code
pro Sekunde (500 MHz Pentium III)
•
Geschwindigkeit ist natürlich abhängig
vom Code
Optimierung des Codes

Es gibt zwei „Stellen“, denen optimiert
werden kann
•
•
Im Sprach-Compiler
Im JIT-Compiler
•
Zur Analyse des Maschinencodes Benutzung
von:
• DebugBreak();


Allgemeine Ergebnisse:
Manches optimiert der Sprach-Compiler,
manches wird vom JIT-Compiler
optimiert
Optimierung des Codes





d += (double)i1 + 7.5 * 11.2 / 2.5;
•
Sprach-Compiler fasst zusammen
for-Schleifen mit wenigen Durchgängen
•
JIT macht Loop-Unrolling
for(i = 5; i < 5; i++)
•
JIT beachtet die Schleife nicht
d += 3 + a – a;
•
JIT erzeugt keinen Code für „+ a - a“
....
Warum C++ unter .NET?





1. Performance
2. Volle Kontrolle
3. Es geht alles
4. Einfacher Zugriff auf „alten“
unmanaged Code
Compiler für 64-bit-Prozessoren
verfügbar
C++ und .NET: Morgen

C++ in Visual Studio 2005 (Whidbey)
•
•
•
•
Neue Features mit C++
•
Optimierungen
C++/CLI – Common Language
Infrastructure
Generische Typen und Templates
Multithreading mit OpenMP
C++: Neues in VS 2005

Neue Syntax   
•
•
•
•
•
•
Elegant und einfach
Natürlich
Verifiable Code
Keine __keywords
Context-sensitive Keywords
•
Wirksam in einem bestimmten Kontext
Spaced Keywords
•
Werden zusammen mit anderen Keywords
benutzt
Neue Syntax




Nachlesen in:
C++/CLI Specification
http://download.microsoft.com/download/
9/9/c/99c65bcd-ac66-482e-8dc10e14cd1670cd/C++%20CLI%20Candidate
%20Base%20Draft.pdf
…schöne URL…
C++ Managed Extensions
public __gc __sealed class Student
{
private:
double m_grade;
String* m_name;
public:
// Property implementation
__property double get_Grade()
{ return m_grade; }
__property void set_Grade(double newGrade)
{ m_grade = newGrade); }
__property String* get_Name()
{ return m_name; }
__property void set_Name(String* newName)
{ m_name = newName; }
};
C++ / CLI morgen
public ref class Student sealed
{
private:
double m_grade;
public:
// Standard property syntax
property double Grade
{
double get() { return m_grade; }
void set(double newGrade) { m_grade = newGrade; }
}
// Trivial property syntax
property String^ Name;
};
Klassen mit „Adjektiven“

Die Klassen erhalten Eigenschaften
class
N { /**/ };
// Nativer Typ
ref class
R { /**/ };
// CLR Referenz-Typ
value class
V { /**/ };
// CLR Werte-Typ
interface class I { /**/ };
// CLR Interface-Klasse
enum class
// CLR Aufzählungs-Typ
E { /**/ };
Instanzierung



Auf dem native Heap: new T
•
Früher: __nogc
Auf dem managed Heap: gcnew T
•
Früher: __gc
Auf dem Stack: T t
Objektzerstörung



Objekte im Garbage Collector
•
•
•
Nicht deterministische Auflösung
Mit „gcnew“
Man bekommt ein „Handle“
Objekte auf dem normalen Heap
•
•
•
Deterministische Auflösung (delete)
Mit „new“
Man bekommt einen Zeiger
Objekte auf dem Stack
•
•
Deterministische Auflösung (Scope)
Nur Deklaration
Zeiger und Referenzen


Zeiger bleiben Zeiger
•
Mit ihren Vor- und Nachteilen
In VS 2005 gibt gcnew ein „Handle“
zurück
•
•
•
•
•
•
Darstellung durch ein „^“ ( “hat”)
Handles sind die Verbindung zu fertigen
Objekten im managed Heap
Keine Pointer-Arithmetik
Keine Konvertierung nach void
Tracking reference operator „%“
Pinning Pointer: pin_ptr
Roadmap C++/CLI



C++/CLI soll standardisiert werden
Oktober 2003: Task Group TG5
•
ISO C++: WG21
Standardisierung: Ende 2004
Update nach C++/CLI







__gc class  ref class
__gc struct  ref struct
__value class  value class
__value struct  value struct
Default-Konstruktoren aus value classes
entfernen
__interface class  interface
class
__interface struct  interface
struct
Update nach C++/CLI









__abstract  abstract (nach hinten)
__sealed  sealed (nach hinten)
__property  property
__event  event
__value enum  enum class
__gc*  ^
__pin  pin_ptr
new  gcnew
0 oder null  nullptr
Update nach C++/CLI






__gc[ ]  array
Alle Instanzen von __box entfernen
„S“ vor den String-Konstanten
entfernen
Explizite Deklaration von überladenen
Operatoren entfernen
__typeof  typeid< >
__try_cast  safe_cast
•
Namensraum stdcli::language
hinzufügen
Generische Typen

C++-Templates
•
•
•
•
•
•
Werden zur Übersetzungszeit expandiert
Zur Laufzeit können keine neuen
Spezialisierungen aufgebaut werden
Die CLR weiss nichts über Templates
Ein generischer Typ kann nicht TypParameter eines Templates sein
•
 Compile-Time-Spezialisierung der Templates
Explizite Spezialisierung erlaubt
•
Verhalten für einen speziellen Typ
Partielle Spezialisierung erlaubt
•
Verhalten für spezielle Argumente
Generische Typen

Generics
•
•
•
•
•
•
Werden zur Laufzeit vom JIT-Compiler
expandiert
Generische Typen können von allen .NETSprachen benutzt werden, egal in welcher
Sprache sie erstellt wurden
In mehreren Assemblies möglich
Der Typ-Parameter darf nicht als
Basisklasse für den generischen Datentyp
verwendet werden
Default-Werte sind nicht erlaubt
JITter kann zur Laufzeit in Abhängigkeit
vom Typ-Parameter optimieren
Generische Typen
generic <typename T>
// template <typename T>
ref class GenType
// ...
{
// T entsprechend benutzen
// ...
};
void _tmain()
{
GenType<typ>^ xxx = gcnew GenType<typ>;
// ...
}
STL

STL kann nun auch mit dem .NETFramework benutzt werden
•

Ist optimiert, um mit managed Code und
managed Daten zu arbeiten
Die gleichen Technologien, die bisher
verwendet wurden, können nun mit der
CLR benutzt werden
Interop






DLL-Aufrufe (P/Invoke)
COM-Aufrufe (RCW und CCW)
„It just works“  „Interop Technologies“
Das gab es alles auch schon in VS 2003!
Übrigens:
.NET-Komponenten können auch aus
unmanaged Code aufgerufen werden
•
•
Bestehende Applikation kann einfach
erweitert werden
Attribut: ClassInterface verwenden
Optimierungen




WPO
•
Whole Program Optimization
Bessere Pentium 4-Unterstützung
Bessere Optimierung beim Linken
Profile Guided Optimization
•
Ablauf-Szenarien werden beim Linken
berücksichtigt
Optimierungen

Profile Guided Optimization (POGO)
Source
Compilieren
ObjectFiles
Link
Instrumented
Image
Instrumented
Image
Scenarios
ObjectFiles
ObjectFiles
Profile
Data
Output
Link
Profile
Data
Optimized
Image
Optimierungen

POGO ermöglicht…
•
•
•
•
Bessere Entscheidungen zum „Inlinen“
von Code
Reorganisation von switch- und if-elseKonstrukten
Codeblöcke können besser angeordnet
werden
•
Weniger Sprünge, weniger Paging
Codeteile können mit unterschiedlichen
Optimierungsoptionen übersetzt werden
Security


In VS 2002: /GS-Schalter
•
Überprüfung auf „Buffer Overrun“
In VS 2005:
• /GS ist standardmäßig eingeschaltet
• Check-Funktion wurde erweitert
•
•
Kopie der „angreifbaren“ Variablen wird
angelegt und ggf. benutzt
Über 400 sichere neue Runtime-Funktionen
•
•
Unsichere Funktionen werden ersetzt
Siehe „strsafe.h“
OpenMP

OpenMP ist eine einfache Möglichkeit
für Multithreading
•
•

Für Fortran (Intel)
Für C++ (Intel, VS 2005)
Normales Multithreading:
•
•
•
•
•
Klasse mit Methode
ThreadStart-Objekt anlegen
Thread-Objekt anlegen
Thread-Methode starten
Synchronisierung mit Join()
OpenMP



Normales Multithreading beinhaltet
einen relativ großen Overhead
Insbesondere wenn Algorithmen
parallelisiert werden sollen
In OpenMP:
•
•
•


Steuerung der Parallelisierung durch C++Pragma im Code
Z.B.: #pragma omp parallel
Steueranweisung stehen direkt im Code
Mit nativem und mit managed Code
Compiler-Schalter: /OPENMP
OpenMP

Es gibt unterschiedliche Arten der
Parallelisierung:
•
•


Parallelisierung von Schleifen
Parallelisierung von Code-Regionen
Nicht zu vergessen:
•
Synchronisierung
Und wie steht‘s mit der Performance?
Schleifen mit OpenMP


Schleifen werden auf mehrere Threads
automatisch aufgeteilt
Anzahl kann angegeben werden oder ist
vom System vorgegeben oder wird
dynamisch ausgewählt
void saxpy(double z[], double a, double x[], double y,
int n)
{
#pragma omp parallel for
for(int i = 0; i < n; i++)
{
z[i] = a * x[i] + y;
}
}
Schleifen mit OpenMP
Serielle Ausführung im Master-Thread
Parallele Ausführung
Automatische Synchronisierung
Serielle Ausführung im Master-Thread
Schleifen mit OpenMP

Das Verfahren kann auch zu Problemen
führen:
void test(double x[], double z[], int n)
{
#pragma omp parallel for
for(int i = 1; i < n; i++)
{
z[i] = x[i] + z[i – 1];
// Fehler!!!
}
}
Schleifen mit OpenMP

Häufig braucht man „Reduktionen“
•
Es gibt mehrere Threads mit eigenen zVariablen, die dann zum Schluss zum
Endergebnis addiert werden
double test(double x[], int n)
{
double z = 0.0;
#pragma omp parallel for reduction(+:z)
for(int i = 1; i < n; i++)
{
z += x[i];
}
return z;
}
Variablen und Scope

Wenn mehrere Threads erzeugt werden,
gibt es zwei Variablen-Arten:
• private: Jeder Thread hat eine eigene
Instanz
• shared: Es gibt nur eine Instanz für alle
Threads


Laufvariablen von Schleifen sind
automatisch „private“
Kann man steuern:
#pragma omp parallel for shared(a, b) private(i, j)
Code-Regionen


Codeteile können ebenfalls parallel
laufen
Anzahl der Threads kann angegeben
werden oder ist vom System
vorgegeben
void test()
{
#pragma omp parallel num_threads(4)
{
Console::WriteLine(„Hallo, TechTalk!“);
}
}
Synchronisierung

Ist fast immer irgendwo erforderlich,
wenn mehrere Threads laufen
• barrier
• critical
• critical(name)
• atomic
•
Operatoren: + - ++ -- * / & ^ | << >>
• master
• flush
• Runtime-Lock

Synchronisierung kostet Zeit!!!
OpenMP-Library

Es gibt diverse Runtime-Methoden in
der OpenMP-Bibliothek:
•
•
•
•
Max. Anzahl der Threads setzen oder
abfragen
Anzahl der vorhandenen Prozessoren
abfragen
Rückgabe einer eindeutigen ThreadNummer
…
OpenMP


Das hört sich ja sehr einfach an…
…es kann aber auch sehr kompliziert
werden
•

Vorsicht beim Programmieren mit
mehreren Threads ist IMMER wichtig
•
•


Das sprengt aber den Rahmen hier!
Immer die Performance prüfen
Immer die Ergebnisse prüfen
OpenMP ist gut für Algorithmen
OpenMP ist nicht gut für die
Parallelisierung von User Interfaces
OpenMP-Performance


ACHTUNG: Performance-Tests sind mit
Alpha- oder Beta-Versionen immer
etwas kritisch!!!
Trotzdem:
•
•
•
Einige Versuche…
…auf Single-Prozessor-Maschine (P4, 2.4
GHz, ohne HyperThreading)
…auf Dual-Prozessor-Maschine (P3, 600
MHz)
OpenMP-Performance

Schleifen-Parallelisierung (Demo16)
Innere Schleife
Threads
ZeitSingle
ZeitDual
20,000
10,000
5,000
2,500
4
4
4
4
2.844 sek
2.284 sek
2.083 sek
1.973 sek
9.937 sek
6.047 sek
4.047 sek
3.010 sek
20,000
20,000
20,000
20,000
4
3
2
1
2.844 sek
2.583 sek
2.393 sek
0.751 sek
9.937 sek
8.791 sek
5.953 sek
9.812 sek
20,000
Ohne
0.631 sek
9.988 sek
OpenMP-Performance

Schleife mit Reduktion (Demo17)
Schleife
Threads
ZeitSingle
ZeitDual
10,000,000
10,000,000
10,000,000
10,000,000
10,000,000
10,000,000
10
6
4
3
2
1
2.494 sek
2.484 sek
2.493 sek
2.473 sek
2.463 sek
2.524 sek
9.922 sek
9.906 sek
9.937 sek
9.921 sek
9.890 sek
16.219 sek
10,000,000
Ohne
2.444 sek
15.853 sek
OpenMP-Performance

Synchronisierung mit „atomic“ oder
„critical“ (Demo18 und Demo19)
Sync.-Typ
Threads
ZeitSingle
ZeitDual
Atomic
Atomic
Atomic
4
2
1
7.210 sek
7.200 sek
7.130 sek
27.501 sek
27.438 sek
15.609 sek
Atomic
Ohne
1.242 sek
7.828 sek
Critical
Critical
Critical
4
2
1
9.245 sek
9.998 sek
8.482 sek
77.047 sek
76.344 sek
18.422 sek
Critical
Ohne
1.242 sek
7.828 sek
Zusammenfassung

C++ Managed Extensions sind HEUTE mit
Visual Studio 2003 NICHT das Teil der Wahl
•
•



Umständlich
Schwer zu lesen
Aber C++ UND .NET kommen wieder
•
•
•
•
C++/CLI
Einfachere Syntax
Gut lesbar, weniger “__” 
Das gesamte .NET-Framework wird unterstützt
In Visual Studio 2005
•
Viele neue Features
•
Optimierungen, OpenMP,…
Wichtig im 64-bit-Umfeld
Buch über OpenMP

Parallel Programming in OpenMP
•
•
•
•
•
R. Chandra, L. Dagum, D. Kohr, D. Maydan,
J. McDonald, R. Menon
Morgen Kaufmann Publishers
ISBN: 1-55860-671-8
Ca. 35 $
Bei Amazon.de oder Amazon.com
Demos und Slides

Download unter:
Fragen?
Uff...