Assignment Chef icon Assignment Chef
All German tutorials

Programming lesson

OpenMP-Multithreading in C++: Nachbarschaftsdurchschnitte berechnen wie ein Profi

Lerne, wie du mit OpenMP in C++ parallele Programme schreibst, um große 2D-Arrays effizient zu verarbeiten – inspiriert von einer typischen CS286-Aufgabe.

OpenMP Multithreading C++ C++ Parallelisierung OpenMP Tutorial CS286 Hausaufgabe Nachbarschaftsdurchschnitt 2D-Array parallel OpenMP Beispiel C++ Performance Wettbewerb dynamische Speicherallokation C++ OpenMP reduction C++ 11 OpenMP Multithreading 2026 C++ für Spieleentwicklung Echtzeit-Analyse C++ OpenMP Schleifen parallelisieren

OpenMP-Multithreading in C++: Nachbarschaftsdurchschnitte berechnen wie ein Profi

Stell dir vor, du analysierst die Bewegungsdaten von 100.000 Spielern in einer Battle-Royale-Runde – jede Sekunde musst du die durchschnittliche Distanz zu den Gegnern in der Nachbarschaft berechnen. Genau solche Herausforderungen meisterst du mit OpenMP in C++. In diesem Tutorial lernst du, wie du mit parallelen Threads große 2D-Arrays durchsuchst und den Zellenwert mit dem höchsten Nachbarschaftsdurchschnitt findest – ganz ohne die Hausaufgabe zu kopieren.

Was ist OpenMP und warum ist es 2026 wichtiger denn je?

OpenMP (Open Multi-Processing) ist eine API für parallele Programmierung in C, C++ und Fortran. Sie ermöglicht es, Schleifen und Codeblöcke mit einfachen Compiler-Direktiven zu parallelisieren. In Zeiten von Multi-Core-Prozessoren in Laptops, Smartphones und Cloud-Servern ist effiziente Parallelisierung der Schlüssel zu schnelleren Berechnungen – egal ob bei KI-Modellen, Finanzsimulationen oder Spiele-Engines.

Der Mai 2026 zeigt: Mit der zunehmenden Verbreitung von Edge-AI und Echtzeit-Analysen wird die Fähigkeit, Multithreading zu beherrschen, zur Grundkompetenz für jeden C++-Entwickler. Unser Tutorial greift eine klassische CS286-Aufgabe auf: Finde die Zelle mit dem höchsten Durchschnitt ihrer Nachbarschaft in einem großen 2D-Array – und das mit OpenMP.

Die Aufgabenstellung im Überblick

Du bekommst eine Textdatei, deren erste Zeile Zeilen- und Spaltenanzahl enthält. Die restlichen Zahlen füllen ein dynamisch allokiertes 2D-Array (z. B. unsigned int** M). Dein Programm muss:

  • Die Nachbarschaft jeder Zelle (3x3-Block, inklusive Zelle selbst) betrachten.
  • Den Durchschnitt der Nachbarschaftswerte berechnen.
  • Die Zelle mit dem höchsten Durchschnitt finden (bei Gleichstand nur eine).
  • Die Ausgabe im Format: largest average: X found at cells: (r,c) liefern.

Optional wird die Ausführungszeit mit einer Stopwatch-Klasse gemessen – perfekt für den internen Wettbewerb um das schnellste Programm.

Schritt 1: Dynamische Speicherallokation mit new

Da das Array riesig sein kann (z. B. 10.000 x 20.000), verwendest du dynamische Speicherallokation auf dem Heap. So geht's:

unsigned int** M = new unsigned int*[rows];
for (int i = 0; i < rows; ++i)
    M[i] = new unsigned int[cols];

Vergiss nicht, den Speicher am Ende freizugeben:

for (int i = 0; i < rows; ++i)
    delete[] M[i];
delete[] M;

Tipp: Nutze std::vector für moderneres C++, aber die Aufgabe verlangt explizit new – also bleiben wir dabei.

Schritt 2: Nachbarschaftsdurchschnitt berechnen – ohne Randfehler

Die Nachbarschaft einer Zelle (r,c) umfasst alle Zellen von r-1 bis r+1 und c-1 bis c+1, die innerhalb des Arrays liegen. Achte darauf, nicht über den Rand hinauszugreifen! Beispiel für Zelle (0,0): Die Nachbarschaft besteht nur aus (0,0), (0,1), (1,0) und (1,1).

Berechne den Durchschnitt als float – die Summe der Nachbarwerte geteilt durch die Anzahl der Nachbarn (zwischen 4 und 9).

Schritt 3: Parallele Suche mit OpenMP

Jetzt kommt der Star: OpenMP. Mit einer einzigen Compiler-Direktive parallelisierst du die äußere Schleife über die Zeilen:

#pragma omp parallel for num_threads(threads)
for (int r = 0; r < rows; ++r) {
    for (int c = 0; c < cols; ++c) {
        // Berechne Durchschnitt und aktualisiere Maximum
    }
}

Damit die Threads sich nicht gegenseitig stören, verwendest du kritische Abschnitte (#pragma omp critical) oder besser Reduktionsvariablen für das Maximum. Ein eleganterer Weg:

#pragma omp parallel for reduction(max:maxAvg) private(r,c,sum,count)
for (int r = 0; r < rows; ++r) {
    for (int c = 0; c < cols; ++c) {
        // ...
        if (avg > maxAvg) maxAvg = avg;
    }
}

Achtung: Die reduction-Klausel funktioniert nur mit einfachen Datentypen. Für die Zellkoordinaten musst du manuell mit einer thread-lokalen Variable und einem kritischen Bereich arbeiten.

Schritt 4: Randbedingungen und Leistungstricks

Um den Wettbewerb zu gewinnen, solltest du:

  • Schleifen zusammenfassen: Vermeide unnötige Berechnungen, indem du die Nachbarschaftssumme effizient berechnest (z. B. mit Integralbildern).
  • Cache-Optimierung: Greife auf das Array zeilenweise zu (row-major order).
  • Thread-Anzahl anpassen: Nutze omp_get_num_procs() für die optimale Anzahl.
  • Dynamische Lastverteilung: Mit schedule(dynamic) wenn die Arbeitslast pro Zelle variiert.

Ein Beispiel für die Zeitmessung mit der Stopwatch-Klasse aus der Vorlage:

stopwatch sw;
sw.start();
// parallele Berechnung
sw.stop();
cout << "elapsed time: " << sw.elapsed() << endl;

Vollständiges Codegerüst (ohne Lösung)

Hier ist ein Grundgerüst, das du anpassen kannst:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <omp.h>
#include <chrono>
using namespace std;

int main(int argc, char* argv[]) {
    // Kommandozeilenargumente parsen
    // Datei oder Zufallsgenerator
    // Array allokieren und füllen
    // Parallele Suche mit OpenMP
    // Ergebnis ausgeben
    // Speicher freigeben
    return 0;
}

Häufige Fehler und wie du sie vermeidest

  • Race Conditions: Verwende #pragma omp critical oder atomic für gemeinsame Variablen.
  • Falsche Randbehandlung: Teste mit kleinen Arrays (z. B. 3x3) und überprüfe die Nachbarschaft manuell.
  • Vergessene Compiler-Flags: Kompiliere mit -fopenmp -std=c++11 (GCC) oder /openmp (MSVC).
  • Nicht-deterministische Ausgabe: Bei Gleichstand musst du eine eindeutige Zelle auswählen – z. B. die zuerst gefundene.

Fazit: OpenMP – dein Turbo für C++-Projekte

Mit OpenMP kannst du aus einem sequenziellen Programm im Handumdrehen eine multithreaded Lösung machen. Die Fähigkeit, große Datenmengen parallel zu verarbeiten, ist 2026 unverzichtbar – ob für KI-Training, Echtzeit-Spiele-Physik oder Finanzanalysen. Nutze dieses Wissen für deine CS286-Aufgabe, aber auch für eigene Projekte. Viel Erfolg beim Wettbewerb um die schnellste Ausführung!