Ich hatte ein Skript, das segfault und ich bin nicht wirklich bequem, wie ich es gelöst habe, also wollte ich die Frage hier zu stellen, um ein wenig mehr über die Ursache davon zu verstehen, und vielleicht eine bessere Lösung.Verständnis von Segfault mit Perl-DBI
Hier ist, was mein Skript macht (entfernt einige detaillierte Code, um den „Kern“, es zu verlassen):
# Here's a query I need to do every X seconds to monitor progress of other tasks
# This is apparently the key to my segfault problem
my $stmt = $dbh->prepare($query);
my $all_done = 0;
while(!$all_done) {
$self->debug("Waiting for $n blocker tasks to be finished");
# Execute query to pull the status of the tasks from DB
$stmt->execute();
my $pending = [];
while(my $hr = $stmt->fetchrow_hashref()) {
push @{$pending}, $hr->{'TASK_NAME'} if ($hr->{'STATUS'} ne 'COMPLETE');
}
if(scalar(@{$pending}) > 0) {
$all_done = 0;
sleep($sleep_gap);
}
else { $all_done = 1; }
}
Nun, das Skript funktioniert gut, die meiste Zeit. Es wird jedoch auf segfault umgestellt, wenn 3 oder mehr Instanzen des Skripts parallel ausgeführt werden () (dasselbe Skript, separate Prozesse, keine Threads).
Wie habe ich es gelöst? Ich löste es, indem ich den DBH :: Prepare-Aufruf jedes Mal während der while (! $ All_done) Schleife machte.
Also, dieser Code segmentiert nicht, auch wenn mehrere Prozesse parallel laufen. Ich reproduzierte den Fehler mehrere Male konsistent, und dann tat ich dasselbe mit dem neuen Code. Ich bin sicher, dass das Verschieben der Anweisung innerhalb der Schleife das Problem BEFESTIGTE.
Irgendwelche Ideen, warum das passieren kann?
Ich benutze Perl 5.8 und Perl-DBI Version 1.609.
Hier ist auch die Ausgabe von strace, wenn das Skript segfaults:
read(5, "\1\7\0\0\6\0\0\0\0\0\20\27\234\312\272\221eG2;\33S\364\230\313\220\221Bxp\4\7"..., 2064) = 263
write(4, "\1\31\0\0\6\0\0\0\0\0\21i \1\1\0\0\0\2\0\0\0\3^!)\4\4\0\0\0\0"..., 281) = 281
read(4, "\0\177\0\0\6\0\0\0\0\0\v\5\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0 \10\6"..., 2064) = 127
write(2, "debug:Waiting for 1 blocker task"..., 49debug:Waiting for 1 blocker tasks to be finished
) = 49
write(5, "\0\252\0\0\6\0\0\0\0\0\3^\20p\200\0\0\2\0\0\0\0\0\0\0\0\1\r\0\0\0\0"..., 170) = 170
read(5, "\0\301\0\0\6\0\0\0\0\0\6\"\2\0\0\[email protected]\0\0\0\0\0\0\0\0\0\0\0\7 ru"..., 2064) = 193
write(5, "\1]\0\0\6\0\0\0\0\0\3^\21)\200\0\0\0\0\0\0\1\234\0\0\0\1\r\0\0\0\0"..., 349) = 349
read(5, "\0y\0\0\6\0\0\0\0\0\10\6\0S\254b\f\0\t\0\0\1\0\0\0\1\0\0\0\0\0\0"..., 2064) = 121
write(5, "\0000\0\0\6\0\0\0\0\0\3h\22\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 48) = 48
read(5, "\0\26\0\0\6\0\0\0\0\0\10\2\0\0\0\t\5\0\0\0\21\0", 2064) = 22
time(NULL) = 1333827285
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({10, 0}, {10, 0}) = 0
time(NULL) = 1333827295
write(4, "\1\31\0\0\6\0\0\0\0\0\21i\"\1\1\0\0\0\3\0\0\0\3^#)\4\4\0\0\0\0"..., 281) = 281
read(4, "\0\177\0\0\6\0\0\0\0\0\v\5\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0 \10\6"..., 2064) = 127
write(2, "debug:Waiting for 1 blocker task"..., 49debug:Waiting for 1 blocker tasks to be finished
) = 49
write(5, "\0)\0\0\6\0\0\0\0\0\21i\23\1\1\0\0\0\1\0\0\0\3N\24\2\0\0\[email protected]\0\0"..., 41) = 41
read(5, "\1>\0\0\6\0\0\0\0\0\20\27\234\312\272\221eG2;\33S\364\230\313\220\221Bxp\4\7"..., 2064) = 318
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
[ Process PID=22767 runs in 32 bit mode. ]
Nur um meinen Beitrag hinzuzufügen, falls es nicht klar genug war: Handeln "prepare()" nur einmal und dann mehrere „execute () "Anrufe sollten der richtige Weg sein, aber so bekomme ich Segfaults. Auf der anderen Seite, indem ich prepare() und execute() die ganze Zeit mache, vermeide ich den segfault. – juansaba
Wird der DBH in dem Thread erstellt, in dem sie verwendet werden? – ikegami
Wenn Sie sagen "mehrere Instanzen" hat das Skript 'fork' oder wurden die Instanzen unabhängig gestartet? – cjm