Multithreaded C Lua-Modul, das zu Segfault in Lua-Skript führt

8


Ich habe eine sehr einfache C-Bibliothek für Lua geschrieben, die aus einer einzigen Funktion besteht, die einen Thread startet, wobei dieser Thread nichts anderes als eine Schleife macht:

%Vor%


Nun, wenn ich ein sehr einfaches Lua-Skript schreibe, das einfach funktioniert:

%Vor%

Das Ausführen des Skripts mit lua myscript.lua führt manchmal zu einem segfault. Hier ist, was GDB über den Core-Dump zu sagen hat:

%Vor%

Mit ein paar Variationen im Stack des Hauptthreads von Zeit zu Zeit.
Es scheint, dass die Funktion start_thread zu einer bestimmten Adresse (in diesem Fall b778b75c) springen möchte, die manchmal zu nicht erreichbarem Speicher gehört.
Bearbeiten
Ich habe auch eine valgrind-Ausgabe:

%Vor%


Mir ging es aber bisher gut, nur den Lua-Interpreter öffnen und manuell nacheinander die gleichen Anweisungen eingeben.
Auch ein C-Programm, das das gleiche tut, mit der gleichen lib:

%Vor%

Wie es sollte, ist bei meinen Tests nie ausgefallen.
Ich habe es mit beiden Lua 5.1 und 5.2 versucht, vergeblich.
Edit: Ich sollte darauf hinweisen, dass ich dies auf einem Single-Core-eeePC mit 32-Bit Debian Wheezy (Linux 3.2) getestet habe. Ich habe gerade wieder auf meinem Hauptcomputer getestet (4-Core 64-Bit-Arch-Linux), und das Skript mit lua myscript.lua segfaults jedes Mal dort gestartet ... Die Eingabe der Befehle von der Interpreter-Eingabeaufforderung aus funktioniert jedoch ebenso gut wie das obige C-Programm.

Der Grund, warum ich diese kleine Lib an erster Stelle geschrieben habe, ist, weil ich eine größere Bibliothek schreibe, mit der ich dieses Problem zuerst hatte. Nach stundenlangem unfruchtbarem Debuggen, einschließlich des Entfernens aller geteilten Strukturen / Variablen nacheinander (ja, ich war so verzweifelt), bin ich auf dieses Stück Code gekommen.
Also, meine Vermutung ist, dass ich etwas falsch mit Lua mache, aber was könnte das sein? Ich habe dieses Problem so oft wie möglich durchsucht, aber ich fand hauptsächlich Leute, die Probleme mit der Verwendung der Lua-API aus mehreren Threads hatten (was ich hier nicht versuche).
Wenn Sie eine Idee haben, würde jede Hilfe sehr geschätzt werden.

Bearbeiten
Um genauer zu sein, würde ich gerne wissen, ob ich zusätzliche Vorsichtsmaßnahmen mit Threads treffen sollte, wenn ich eine C-Lib für die Verwendung in Lua-Skripten schreibe. Benötigt Lua Threads, die innerhalb einer dynamisch geladenen Bibliothek erstellt wurden, um beim Entladen der Bibliothek beendet zu werden?

    
ranjak 15.02.2015, 15:12
quelle

2 Antworten

2

Warum passiert der Segfault im Lua-Modul?

Ihr Lua-Skript wird beendet, bevor der Thread beendet ist, was den segfault verursacht. Das Lua-Modul wird während des normalen Interpreter-Shutdowns mit dlclose() entladen. Daher werden die Anweisungen des Threads aus dem Speicher entfernt, und beim Lesen der nächsten Anweisung wird das Lua-Modul automatisch gelöscht.

Welche Optionen gibt es?

Jede Lösung, die die Threads stoppt, bevor das Modul entladen wird, funktioniert. Die Verwendung von pthread_join() im Haupt-Thread wartet auf das Ende der Threads (Sie möchten möglicherweise lange laufende Threads mit pthread_cancel() beenden). Das Aufrufen von pthread_exit() im Hauptthread vor dem Entladen des Moduls verhindert ebenfalls den Absturz (weil dlclose() verhindert wird), bricht aber auch die normale Bereinigungs- / Herunterfahrprozedur des Lua-Interpreters ab.

Hier sind einige Beispiele, die funktionieren:

%Vor%

Nun wird das Skript schön beendet:

%Vor%

Um dies zu automatisieren, können Sie sich an den Garbage Collector binden, da alle Objekte im Modul vor dem Entladen des gemeinsamen Objekts freigegeben werden. (wie der Großwolf vorgeschlagen hat)

  

Diskussion zum Aufruf von pthread_exit () von main (): Es gibt ein definitives Problem, wenn main () endet vor den Threads, die es hervorbrachte, wenn   Sie rufen pthread_exit () nicht explizit auf. Alle Fäden es   created wird beendet, weil main () fertig ist und nicht mehr existiert   Unterstütze die Fäden. Indem Sie main () explizit pthread_exit () aufrufen   Als letztes wird main () blockiert und am Leben gehalten   unterstützt die erstellten Threads, bis sie fertig sind.

(Dieses Zitat ist ein wenig irreführend: Die Rückgabe von main() entspricht in etwa dem Aufruf von exit() , wodurch der Prozess einschließlich aller laufenden Threads beendet wird. Dies kann oder kann nicht genau das gewünschte Verhalten sein. Wenn Sie pthread_exit() im Haupt-Thread aufrufen, wird der Haupt-Thread beendet, aber alle anderen Threads bleiben so lange aktiv, bis sie von alleine aufhören oder jemand anderes sie tötet. Auch dies kann das gewünschte Verhalten sein oder auch nicht kein Problem, es sei denn, Sie wählen die falsche Option für Ihren Anwendungsfall.)

    
rpattiso 17.02.2015, 10:50
quelle
0

Also, es scheint, dass ich tun sicherstellen muss, dass alle meine Threads beendet sind, wenn Lua meine lib entlädt.

Eine Lösung

Ich kann festlegen, dass eine Bereinigungsfunktion aufgerufen wird, wenn die Bibliothek entladen wird.
Innerhalb dieser Funktion kann ich sicherstellen, dass alle Threads, die meine lib gestartet haben, beendet wurden. Der Aufruf von pthread_exit könnte einfach sein, wenn ich Threads gelöst habe, die noch laufen, aber ich bin mir nicht sicher, wie sicher / sauber es ist, da es Lua abrupt unterbricht ...
Wie auch immer, ich kann dies erreichen, indem ich ein metatable mit einem __gc -Feld erzeuge, das auf meine Aufräumfunktion gesetzt ist, und dann dieses metatable auf meine lib's Tabelle in Lua 5.2 anwenden.

%Vor%

In Lua 5.1 funktioniert die Option __gc nur für Benutzerdaten. Es gibt mehrere Lösungen, um es in meinem Fall zum Laufen zu bringen:
- Lua shutdown / Ende des Rückrufs für die Programmausführung
- Ссылка (siehe 'Warum funktionieren die __gc und __len Metamethoden nicht auf Tabellen?')
- Die Lösung von Greatwolf, ein globales Objekt mit dem angefügten Metatable zu haben.

    
ranjak 16.02.2015 12:26
quelle

Tags und Links