我有一段腳本正在執行段錯誤,而且我解決這個問題的方式並不舒服,因此我想在此處發佈問題以更多地瞭解它的原因,並且也許更好的解決方案。使用perl-DBI瞭解Segfault
這裏是我的腳本做什麼(刪除了一些詳細的代碼離開「核心」的話):
# 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; }
}
現在,腳本運行良好,大部分時間。但是,當腳本的3個或更多實例並行運行(相同的腳本,單獨的進程,而不是線程)時,它會進入段錯誤。
我是如何解決它的? 我通過在while(!$ all_done)循環中每次執行DBH :: prepare調用來解決它。
因此,即使有多個進程並行運行,此代碼也不會發生段錯誤。我一再重複了這個錯誤,然後對新代碼做了同樣的處理。我肯定的是,在循環內移動語句修復了這個問題。
任何想法,爲什麼會發生這種情況?
我使用的是perl 5.8和perl-DBI版本1.609。
這裏也是strace的時候輸出腳本段錯誤:
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. ]
只需添加到我的帖子,在情況下,它是不夠清楚:做「準備()」只有一次,然後多個「執行( )「調用應該是正確的方式來做到這一點,但這樣我就會發生段錯誤。另一方面,通過一直執行prepare()和execute()來避免段錯誤。 – juansaba 2012-04-07 20:41:20
是否在使用它們的線程中創建了DBH? – ikegami 2012-04-07 20:49:04
當你說「多個實例」做了'fork'腳本還是實例獨立啓動? – cjm 2012-04-08 00:08:19