\item\textbf{Datenebene}: Es kommt immer wieder vor, dass man in Schleifen
eine Operation für jedes Objekt eines Contaitainers (z.~B. einer Liste)
durchführen muss. Zwischen den Anweisungen verschiedener Schleifendurchläufe
besteht dann eventuell keine Abhängigkeit. Dann können alle Schleifenaufrufe
parallel durchgeführt werden.
\item\textbf{Verarbeitungsebene}: Verschiedene Programme sind unabhängig
von einander.
\end{itemize}
Gerade bei dem letzten Punkt ist zu beachten, dass echt parallele Ausführung nicht mit \textit{verzahnter Ausführung}\xindex{verzahnt} zu verwechseln ist. Auch bei Systemen mit nur einer CPU und einem Kern kann man gleichzeitig den Browser nutzen und einen Film über eine Multimedia-Anwendung laufen lassen. Dabei wechselt der Scheduler sehr schnell zwischen den verschiedenen
Anwendungen, sodass es sich so anfühlt, als würden die Programme echt parallel
ausgeführt werden.
Weitere Informationen zu Pipelining gibt es in der Vorlesung \enquote{Rechnerorganisation}
bzw. \enquote{Digitaltechnik und Entwurfsverfahren} (zu der auch ein exzellentes Skript angeboten wird). Informationen über Schedulung werden in der Vorlesung \enquote{Betriebssysteme}
vermittelt.
\section{Architekturen}
Es gibt zwei Ansätze, wie man Parallelrechner entwickeln kann:
\begin{itemize}
\item\textbf{Gemeinsamer Speicher}: In diesem Fall kann jeder Prozessor
jede Speicherzelle ansprechen. Dies ist bei Multicore-CPUs der Fall.
\item\textbf{Verteilter Speicher}: Es ist auch möglich, dass jeder Prozessor
seinen eigenen Speicher hat, der nur ihm zugänglich ist. In diesem Fall
schicken die Prozessoren Nachrichten (engl. \textit{message passing}\xindex{message passing}). Diese Technik wird in Clustern eingesetzt.
\end{itemize}
Eine weitere Art, wie man Parallelverarbeitung klassifizieren kann, ist anhand
der verwendeten Architektur. Der der üblichen, sequentiellen Art der Programmierung,
bei der jeder Befehl nach einander ausgeführt wird, liegt die sog.
Bei der Programmierung von parallel laufenden Anwendungen kann man das \textbf{PRAM-Modell}\xindex{PRAM-Modell} (kurz für \textit{Parallel Random Access Machine}) zugrunde legen.
In diesem Modell geht man von einer beliebigen Anahl an Prozessoren aus, die
über lokalen Speicher verfügen und synchronen Zugriff auf einen gemeinsamen
Speicher haben.
Anhand der \textbf{Flynn'schen Klassifikation}\xindex{Flynn'sche Klassifikation}
können Rechnerarchitekturen in vier Kategorien unterteilt werden:
Monitore können mit einer Semaphore, bei der $c=1$ ist, implementiert werden.
Monitore sorgen dafür, dass auf die Methoden der Objekte, die sie repräsentieren,
zu jedem Zeitpunkt nur ein mal ausgeführt werden können. Sie sorgen also für
\textit{gegenseitigen Ausschluss}.
\begin{beispiel}[Monitor]
Folgendes Beispiel von \url{https://en.wikipedia.org/w/index.php?title=Monitor_(synchronization)&oldid=596007585} verdeutlicht den Nutzen eines Monitors:
\begin{verbatim}
monitor class Account {
private int balance := 0
invariant balance >= 0
public method boolean withdraw(int amount)
precondition amount >= 0
{
if balance < amount:
return false
else:
balance := balance - amount
return true
}
public method deposit(int amount)
precondition amount >= 0
{
balance := balance + amount
}
}
\end{verbatim}
\end{beispiel}
\section{Parallelität in Java}
Java unterstützt mit der Klasse \texttt{Thread} und dem Interface \texttt{Runnable}