Programmierung in Ruby

Der Leitfaden der Pragmatischen Programmierer

Threads und Prozesse



In Ruby gibt es zwei grundlegende Arten, wie man ein Programm so organisieren kann, dass unterschiedliche Teile ``zur gleichen Zeit'' laufen. Man kann mehrere kooperative Aufgaben innerhalb eines Programms über unterschiedliche Threads laufen lassen oder man kann mehrere Aufgaben in verschiedenen Programmen über unterschiedliche Prozesse laufen lassen. Wir werden beides besprechen.

Multithreading

Zwei Dinge gleichzeitig zu machen ist meist am einfachsten, wenn man Ruby-Threads benutzt. Die existieren nur im Ruby-Interpreter. Das macht Ruby völlig portabel --- unabhängig vom Betriebssystem --- aber es fehlen auch einige Vorteile von Original-Threads. Einzelne Threads können einem verhungern (wenn Threads mit niedriger Priorität nicht an die Reihe kommen). Wenn ein Thread sich aufhängt, kann der gesamte Prozess blockiert werden. Und wenn ein Thread einen Betriebssystem-Aufruf macht, der etwas länger dauert, dann hängen alle anderen Threads so lange, bis der Interpreter wieder die Konrtrolle zugesprochen bekommt. Trotzdem sollte man sich von solchen potentiellen Problemen nicht abschrecken lassen --- mit Ruby-Threads kann man auf einfache und effiziente Art eine Parallelisierung erreichen.

Ruby-Threads erzeugen

Das Erzeugen eines neuen Threads ist schnell gemacht. Hier ist ein einfaches Beispiel, das eine Reihe von Web-Seiten parallel lädt. Für jede Anfrage erzeugt der Code einen neuen Thread, der die HTTP-Transaktion ausführt.

require 'net/http'

pages = %w( www.rubycentral.com             www.awl.com             www.pragmaticprogrammer.com            )

threads = []

for page in pages   threads << Thread.new(page) { |myPage|

    h = Net::HTTP.new(myPage, 80)     puts "Fetching: #{myPage}"     resp, data = h.get('/', nil )     puts "Got #{myPage}:  #{resp.message}"   } end

threads.each { |aThread|  aThread.join }

erzeugt:
Fetching: www.rubycentral.com
Fetching: www.awl.com
Fetching: www.pragmaticprogrammer.com
Got www.rubycentral.com:  OK
Got www.pragmaticprogrammer.com:  OK
Got www.awl.com:  OK

Schauen wir uns den Code mal etwas näher an, es passieren dort nämlich einige subtile Dinge.

Neue Threadds werden mit dem Thread.new-Aufruf erzeugt. Der bekommt einen Block mit, der den Code enthält, der in diesem neuen Thread laufen soll. In unserem Fall benutzt der Block die net/http-Bibliothek, um sich die erste Seite jeder gewünschten Site zu holen. Das Tracing zeigt ganz klar, dass dieses Holen parallel abläuft.

Wenn wir den Thread erzeugen, übergeben wir die gewünschte HTML-Seite als Parameter. Dieser Parameter wird dem Block als myPage übergeben. Warum machen wir das so, warum benutzen wir nicht einfach den Wert der Variablen page innerhalb des Blocks?

Threads teilen alle globalen, Instanz- und lokalen Variablen, die zum Zeitpunkt ihrer Entstehung existierten. Wer einen kleinen Bruder hat, weiß, dass Teilen nicht immer so schön ist. In diesem Fall würden sich alle drei Threads die Variable page teilen. Der erste Thread wird gestartet und page wird auf http://www.rubycentral.com gesetzt. Währenddessen läuft die Schleife, die die Threads erzeugt, weiter. Beim zweiten Durchgang wird page auf http://www.awl.com gesetzt. Wenn der erste Thread noch nicht fertig ist mit der Variablen page, dann wird er jetzt deren neuen Wert benutzen. Solche Fehler sind nur sehr schwer nachzuvollziehen.

Allerdings sind lokale Variablen, die innerhalb eines Block erzeugt werden, auch wirklich lokal für diesen Thread --- jeder Thread arbeitet mit einer eigenen Kopie dieser Variablen. In unserem Fall wird die Variable myPage gesetzt, wenn der Thread erzeugt wird, und jeder Thread besitzt seine eigene Kopie der Web-Adresse.

Threads manipulieren

Eine andere Subtilität taucht in der letzten Zeile des Programms auf. Warum rufen wir join für jeden erzeugten Thread auf?

Wenn ein Ruby-Programm beendet wird, werden alle noch laufenden Threads abgeschossen, egal wie ihr Status ist. Man kann allerdings auf das Beenden eines speziellen Thread warten, wenn man die Thread#join-Methode dieses Threads aufruft. Der aufrufende Thread wird so lange blockiert, bis der gewünschte Thread beendet ist. Durch den Aufruf von join für jeden der gewünschten Threads geht man sicher, dass alle drei Threads beendet werden, bevor man das Hauptprogramm beendet.

Darüber hinaus gibt es noch ein paar andere nützliche Routinen, mit denen man Threads manipulieren kann. Zunächst einmal kann man den aktuellen Thread ermitteln mit Thread.current. Man erhält eine Liste mit allen Threads mit Thread.list, das liefert eine Liste von allen Thread-Objekten, die lauffähig oder gerade gestoppt sind. Um den Status eines bestimmten Threads zu ermitteln, kann man Thread#status und Thread#alive? benutzen.

Außerdem kann man die Priorität eines Thread mit Thread#priority= setzen. Threads mit höherer Priorität laufen vor solchen mit niedrigerer. Wir werden gleich über die Laufzeitaufteilung von Threads sprechen und darüber, wie man sie startet und stoppt.

Thread-Variablen

Wie wir schon im vorherigen Abschnitt beschrieben haben, kann ein Thread ganz normal auf alle Variablen der Umgebung zugreifen, in der er erzeugt wurde. Variablen, die im Thread-Block lokal sind, sind in diesem Thread lokal und sind für andere nicht erreichbar.

Was aber, wenn man thread-eigene Variablen braucht, auf die von andern Threads --- auch vom Haupt-Thread --- aus zugegriffen werden soll? Thread besitzt dafür eine Eigenschaft, mit der man thread-eigene Variablen erzeugen und über den Namen ansprechen kann. Man behandelt das Thread-Objekt einfach, als wäre es ein Hash, und schreib in Elemente mit []= und liest sie mit []. In diesem Beipiel hält jeder Thread den aktuellen Wert der Variable count in einer thread-lokalen Variablen unter dem Schlüssel mycount. (Es gibt da ein kleines Problem mit Zugriffskollisionen in diesem Code, aber bis jetzt haben wir noch nicht über Synchronisation gesprochen, also ignorieren wir das erstmal.)

count = 0
arr = []
10.times do |i|
  arr[i] = Thread.new {
    sleep(rand(0)/10.0)
    Thread.current["mycount"] = count
    count += 1
  }
end
arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"
erzeugt:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10

Der Haupt-Thread wartet auf das Beenden der Unter-Threads und gibt dann den von jedem erhaltenen Wert von count aus. Um das ein wenig interessanter zu machen, lassen wir jeden Thread eine zufällige Zeitspanne warten, bis er den Wert zurückliefert.

Threads und Exceptions

Was passiert, wenn ein Thread eine nicht abgefangene Exception auslöst? Das kommt auf den Wert vom http://abort_on_exception-Flag an, beschrieben auf Seite 389 und 392.

Wenn abort_on_exception false ist, (das ist der Default-Zustand) dann schießt eine unbehandelte Exception einfach nur den aktuellen Thread ab --- der ganze Rest läuft weiter. Im folgenden Beispiel wird Thread Nummer 3 hochgehen und keinerlei Output erzeugen. Trotzdem kann man immer noch die Ergebnisse der anderen Threads sehen.

threads = []
6.times { |i|
  threads << Thread.new(i) {
    raise "Boom!" if i == 3
    puts i
  }
}
threads.each {|t| t.join }
erzeugt:
01
2
4
5

prog.rb:4: Boom! (RuntimeError) from prog.rb:8:in `join' from prog.rb:8 from prog.rb:8:in `each' from prog.rb:8

Wenn man allerdings abort_on_exception auf true setzt, dann killt eine nicht behandelte Exception alle anderen Threads. Wenn jetzt Thread 3 stirbt, wird kein Output mehr erzeugt.

Thread.abort_on_exception = true
threads = []
6.times { |i|
  threads << Thread.new(i) {
    raise "Boom!" if i == 3
    puts i
  }
}
threads.each {|t| t.join }
erzeugt:
01
2
prog.rb:5: Boom! (RuntimeError)
	from prog.rb:7:in `initialize'
	from prog.rb:7:in `new'
	from prog.rb:7
	from prog.rb:3:in `times'
	from prog.rb:3

Kontrolle des Thread-Schedulers

In einer gut designten Applikation läßt man normalerweise die Threads ihre Arbeit machen und mischt sich nicht ein; Zeit-Abhängigkeiten in eine Multi-Thread-Applikation einzubauen wird allgemein als schlechter Stil angesehen.

Trotzdem gibt es Gelegenheiten, wo man die Threads kontrollieren muss. Vielleicht hat die Jukebox einen Thread zum Steuern der Light-Show. Das müssen wir unterbrechen können, wenn gerade keine Musik läuft. Man kann auch zwei Threads in einer klassischen Erzeuger-Benutzer Beziehung haben, wo der Benutzer eine Pause einlegen muss, wenn der Erzeuger in Rückstand gerät.

Die Klasse Thread besitzt eine Anzahl von Methoden, um den Thread-Scheduler zu kontrollieren. Der Aufruf von Thread.stop stoppt den aktuellen Thread, während Thread#run dafür sorgt, dass ein bestimmter Thread läuft. Thread.pass unterbricht den aktuellen Thread, damit andere auch mal drankommen, und Thread#join und Thread#value hält den aufrufenden Thread solange an, bis der angegebene Thread beendet ist.

Wir demonstrieren diese Eigenschaften mit folgendem völlig bedeutungslosen Programm.

t = Thread.new { sleep .1; Thread.pass; Thread.stop; }
t.status » "sleep"
t.run
t.status » "run"
t.run
t.status » false

Der Versuch, mit solch einfachen Dingen echte Synchronisation zu erreichen, ist allerdings bestenfalls Glückssache; man läuft immer Gefahr, von Zugriffskollisionen erwischt zu werden. Wenn man mit gemeinsam benutzten Daten arbeitet, dann sind Zugriffskollisionen eine ausgezeichtnete Garantie für lange und frustrierende Debug-Sitzungen. Glücklcherweise besitzen Threads noch eine weitere Eigenschaft --- die Idee der Critical Section. Mit dieser kann man eine Reihe von sicheren Synchonisations-Schemas erzeugen.

Gegenseitiger Ausschluss

Die niedrigst levelige Methode zum Blockieren anderer Threads benutzt einen globalen ``thread critical''-Zustand. Wenn dieser Zustand auf true gesetzt ist (mit der Thread.critical=-Methode), dann wird der Scheduler keinem anderen existierenden Thread die Kontralle zuteilen. Allerdings blockiert das nicht die Erzeugung und den Ablauf von neuen Threads. Bestimmte Thread-Operationen (wie etwa Stoppen oder Killen eines Threads, Schlafenlegen des aktuellen Threads oder das Auslösen einer Exception) können einen Thread zur Ausführung bringen, auch wenn man gerade in einer Critical Section ist.

Es ist natürlich möglich, Thread.critical= direkt zu benutzen, aber es ist nicht so besonders überzeugend. Glücklicherweise gibt es in Ruby zusätzlich noch verschiedene Alternativen. Davon sind zwei der besten die Klasse Mutex und die Klasse ConditionVariable aus dem thread-Bibliotheks-Modul; siehe die Dokumantation ab Seite 462.

Die Mutex Klasse

Die Klasse Mutex benutzt eine einfache Semaphore-Blockierung für den gegenseitigen Ausschluss des Zugriffs auf gemeinsame Daten. Das bedeutet, dass immer nur ein Thread zur Zeit die Blockierung besitzt. Andere Threads können sich entscheiden, zu warten, bis die Blockierung für sie verfügbar ist oder sie melden einfach den Fehler, dass die Blockierung nicht verfügbar ist.

Ein Mutex wird oft benutzt, wenn ein Update auf gemeinsam benutzte Daten nur vollständig ablaufen darf. Sagen wir, das Update soll im Rahmen einer Transaktion zwei Variablen ändern. Wir können das in einem einfachen Programm simulieren, indem wir zwei Zähler hochzählen. Die Änderungen sollten simultan laufen --- von außen sollte man niemals verschiedene Werte sehen. Ohne irgendeine Art von Mutex-Kontrolle klappt das gar nicht.

count1 = count2 = 0
difference = 0
counter = Thread.new do
  loop do
    count1 += 1
    count2 += 1
  end
end
spy = Thread.new do
  loop do
    difference += (count1 - count2).abs
  end
end
sleep 1
Thread.critical = 1
count1 » 187651
count2 » 187650
difference » 77442

Dieses Beispiel zeigt, dass der ``Spy''-Thread bei seinen jeweiligen Durchläufen sehr oft unterschiedliche Werte von count1 und count2 vorgefunden hat.

Glücklicherweise können wir das mit einem Mutex bereinigen.

require 'thread'
mutex = Mutex.new

count1 = count2 = 0 difference = 0 counter = Thread.new do   loop do     mutex.synchronize do       count1 += 1       count2 += 1     end   end end spy = Thread.new do   loop do     mutex.synchronize do       difference += (count1 - count2).abs     end   end end

sleep 1
mutex.lock
count1 » 21636
count2 » 21636
difference » 0

Wir sichern die Konsistenz, indem wir alle Zugriffe auf die gemeinsamen Daten unter die Kontrolle eines Mutex stellen. Unglücklicherweise leidet die Performance darunter, wie man auch an den Zahlen sehen kann.

Condition-Variablen

Manchmal genügt ein Mutex nicht, um kritische Daten zu schützen. Man stelle sich vor, man ist in einer critical Section, muss aber auf irgendwelche anderen Resourcen warten. Wenn der Thread dann schlafen geht, während er auf diese Resource wartet, ist es möglich, dass kein anderer Thread in der Lage ist, diese Resource zu liefern --- der ursprüngliche Thread hält ja immer noch eine Blockierung darauf. Man müsste in der Lage sein, die exklusive Nutzung einer kritischen Region aufzugeben und gleichzeitig allen anderen zu sagen, dass man euf eine Resource wartet. Wenn die Resource dann verfügbar wird, muss man sie greifen können und gleichzeitig die Blockierung der kritischen Region zurückerlangen.

Dafür gibt es Condition-Variablen. Eine Condition-Variable ist einfach eine Semaphore, die mit einer Resource verbunden ist, die unter dem Schutz eines bestimmten Mutex benutzt wird. Wenn man eine gerade nicht verfügbare Resource benötigt, bedient man eine Condition-Variable. Diese Aktion gibt die Blockierung auf den dazu gehörenden Mutex frei. Wenn ein anderer Thread dann signalisiert, dass die Resource verfügbar ist, hört der ursprüngliche Thread auf, zu warten, und erhält gleichzeitig die Blockierung auf die kritische Region.

require 'thread'
mutex = Mutex.new
cv = ConditionVariable.new

a = Thread.new {   mutex.synchronize {     puts "A: I have critical section, but will wait for cv"     cv.wait(mutex)     puts "A: I have critical section again! I rule!"   } }

puts "(Later, back at the ranch...)"

b = Thread.new {   mutex.synchronize {     puts "B: Now I am critical, but am done with cv"     cv.signal     puts "B: I am still critical, finishing up"   } } a.join b.join
erzeugt:
A: I have critical section, but will wait for cv(Later, back at the ranch...)

B: Now I am critical, but am done with cv B: I am still critical, finishing up A: I have critical section again! I rule!

Andere Implementationen von Synchronisierungs-Mechanismen findet man bei monitor.rb und sync.rb im lib-Unterverzeichnis der Distribution.

Multiple Prozesse laufen lassen

Manchmal möchte man eine Aufgabe in verschiedene prozess-große Teile aufspalten --- oder vielleicht muss man einen seperaten Prozess laufen lassen, der nicht in Ruby geschrieben wurde. Kein Problem: Ruby besitzt eine Anzahl von Methoden, mit denen man unterschiedliche Prozesse hervorbringen und kontrollieren kann.

Produzieren neuer Prozesse

Es gibt verschiedene Möglichkeiten, einen seperaten Prozess zu produzieren; der einfachste ist, irgendein Kommando laufen zu lassen und auf dessen Abschluss zu warten. Man kann das machen, um ein separates Kommando ablaufen zu lassen oder um Daten vom Host zu bekommen. Ruby macht das mit den system- und Backquote-Methoden.

system("tar xzf test.tgz") » tar (child): Cannot open archive test.tgz: No such file or directory\ntar (child): Error is not recoverable: exiting now\ntar: Child returned status 2\ntar: Error exit delayed from previous errors\nfalse
result = `date`
result » "Sun Mar  4 23:24:12 CST 2001\n"

Die Methode Kernel::system führt das gegebene Kommando in einem Subprozess aus; sie gibt true zurück, wenn das Kommando gefunden und erfolgreich ausgeführt wurde, sonst false. Im Falle eines Fehlschlags findet man den Rückgabecode in der globalen Variablen $?.

Ein Problem mit system ist, dass das Kommando einfach seinen Output auf das selbe Ziel schreibt, wie das Programm, meistens möchte man das nicht. Um den Standard-Output eines Subprozesses abzufangen, kann man Backquotes benutzen wie bei `date` im vorherigen Beispiel. Man denke aber daran, das man eventuell String#chomp braucht, um etwaige Zeilenende-Zeichen vom Ergebnis abzuschneiden.

Okay, für einfache Fälle ist das ja ganz schön --- wir lassen einige ander Prozesse laufen und warten auf ihre Rückgabe. Aber oft braucht man ein bisschen mehr Kontrolle. Wir wollen uns mit dem Subprozess unterhalten, vielleicht ein paar Daten schicken oder auch zurückerhalten. Die Methode IO.popen macht genau dies. Die popen-Methode lässt ein Kommando als Subprozess laufen und verbindet dessen Standard-Input und Standard-Output mit einem Ruby-IO-Objekt. Man schreibt in dieses IO-Objekt und der Subprozess kann das über seinen Standard-Input lesen. Und was der Subprozess schreibt ist im Ruby-Programm lesbar als Output des IO-Objekts.

Als Beispiel zeigen wir hier eins unserer nützlicheren Utilities, pig, ein Programm, das Wörter vom Standard-Input liest und sie in Pig-Latin (oder igPay,atinLay) wieder ausgibt. Wir benutzen das, wenn unsere Ruby-Programme Sachen ausgeben sollen, die unsere 5-jährigen Kinder nicht lesen sollen.

pig = IO.popen("pig", "w+")
pig.puts "ice cream after they go to bed"
pig.close_write
puts pig.gets
erzeugt:
iceway eamcray afterway eythay ogay otay edbay

Dieses Beispiel zeigt zugleich die anscheinende Einfachheit und die tatsächliche Komplexität, wenn man Subprozesse durch Pipes schickt. Der Code sieht sicher ganz einfach aus: öffne die Pipe, schreibe einen Satz und lese die Ausgabe. Aber es stellt sich heraus, dass das pig-Programm den von ihm geschriebenen Output nicht weiterleitet. Unser erster Versuch mit diesem Beispiel, mit pig.puts gefolgt von pig.gets, blieb einfach für immer hängen. Das pig-Programm bearbeitete den Input, aber das Ergebnis wurde nie in die Pipe geschrieben. Wir mussten pig.close_write einfügen. Das schickte ein end-of-file an den Standard-Input von pig und der Output, auf den wir gewartet hatten, wurde weitergeleitet, sobald pig beendet wurde.

Es gibt da eine weitere Eigenheit bei popen. Wenn das übergebene Kommando ein einzelnes Minuszeichen ist (``--''), so wird popen in einen neuen Ruby-Interpreter aufspalten. Beide, dieser und der Original-Interpreter, werden weiterlaufen, wenn popen beendet wird. Der Original-Prozess erhält ein IO-Objekt zurück, während der Kind-Prozess ein nil erhält.

pipe = IO.popen("-","w+")
if pipe
  pipe.puts "Get a job!"
  $stderr.puts "Child says '#{pipe.gets.chomp}'"
else
  $stderr.puts "Dad says '#{gets.chomp}'"
  puts "OK"
end
erzeugt:
Dad says 'Get a job!'
Child says 'OK'

Zusätzlich zu popen sind die üblichen Unix-Aufrufe Kernel::fork, Kernel::exec und IO.pipe verfügbar, wenn die Plattform das unterstützt. Genauso produziert die Dateinamenskonvention von vielen IO-Methoden und Kernel::open Subprozesse, wenn man ein ``|'' vor den Dateinamen setzt (ausführlicher ist das in der Einleitung zur IO-Klasse auf Seite 329 beschrieben). Beachte, dass man mit File.new keine Pipes erzeugen kann; das ist nur für Dateien.

Unabhängige Kinder

Manchmal brauchen wir nicht so rigide zu sein: Wir geben dem Subprozess seinen Auftrag und gehen danach unserer Wege. Später schauen wir nach, ob er schon fertig ist. Als Beispiel starten wir eine lang dauernde externe Sortierung.

exec("sort testfile > output.txt") if fork == nil
# The sort is now running in a child process
# carry on processing in the main program

# then wait for the sort to finish Process.wait

Der Aufruf von Kernel::fork gibt dem Elternteil eine Prozess-Id zurück und dem Kind nil, so dass der Kindprozess den Kernel::exec-Aufruf ausführt und die Sortierung startet. Irgendwann später setzen wir einen Process::wait-Aufruf ab, der auf das Ende der Sortierung wartet (und ihre Prozess-Id zurückgibt).

Wenn man lieber benachrichtigt werden will, wenn der Kindprozess fertig ist (statt nur herumzuwarten), kann man einen Signal-Hnadler aufstellen mit Kernel::trap (beschrieben auf Seite 431). Hier fangen wir SIGCLD ab, das Signal für ``death of child process'' (Tod des Kindprozesses).

trap("CLD") {
  pid = Process.wait
  puts "Child pid #{pid}: terminated"
  exit
}

exec("sort testfile > output.txt") if fork == nil

# do other stuff...

erzeugt:
Child pid 14481: terminated

Blöcke und Unterprozesse

IO.popen arbeitet mit einem Block in etwa genauso wie File.open. Man gibt popen ein Kommando mit, etwa date, und der Block wird an das IO-Objekt als Parameter weitergereicht.

IO.popen ("date") { |f| puts "Date is #{f.gets}" }
erzeugt:
Date is Sun Mar  4 23:24:12 CST 2001

Das IO-Objekt wird automatisch geschlossen, wenn der Block beendet wird, genauso wie bei File.open.

Wenn man einen Block einem Kernel::fork zuordnet, wird der Code-Block in einem Ruby-Unterprozess ausgeführt, und der Elternteil arbeitet nach dem Block weiter.

fork do
  puts "In child, pid = #$$"
  exit 99
end
pid = Process.wait
puts "Child terminated, pid = #{pid}, exit code = #{$? >> 8}"
erzeugt:
In child, pid = 14488
Child terminated, pid = 14488, exit code = 99

Noch eine letzte Sache. Warum haben wir den Exit-Code aus $? vor der Anzeige 8 Bits nach rechts geschoben? Das ist eine ``Eigenheit'' von Posix-Systemen: die unteren 8 Bits des Exit-Codes enthalten den Grund für das Programmende, während die oberen 8 Bits den tatsächlichen Exit-Code enthalten.


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Übersetzung: Jürgen Katins
Für das englische Original:
© 2000 Addison Wesley Longman, Inc. Released under the terms of the Open Publication License V1.0. That reference is available for download.
Diese Lizenz sowie das Original vom Herbst 2001 bilden die Grundlage der Übersetzung
Es wird darauf hingewiesen, dass sich die Lizenz des englischen Originals inzwischen geändert hat.
Für die deutsche Übersetzung:
© 2002 Jürgen Katins
Der Copyright-Eigner stellt folgende Lizenzen zur Verfügung:
Nicht-freie Lizenz:
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
Freie Lizenz:
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".