2 つのスレッド間のあいまいなロックアップは、グローバル インタープリター ロックまたはその他の「舞台裏のロック」に関連しているようで、トラブルシューティングを続行する方法がわかりません。ロックアップを解消するためのヒントをいただければ幸いです。
この問題は、より大きなコード セットで再現されます (不規則かつランダムに発生します)。コードは厳密に python です。Python のバージョンは 2.6.5 (Linux 上) です。何時間ものトラブルシューティングにより、ロックアップが発生したときの問題が次のように軽減されました。
- プログラムには実行中のスレッドが 2 つしかありません
- スレッドは、単一のスレッド化によって保護されたメソッドを同時に呼び出します.RLock
- スレッド 1 は、acquire() を介してロック [およびその他のロック] を取得しました
- スレッド 2 は acquire() を呼び出しており、ロックを待機していることが確認されています
- スレッド 1 は、print() を使用してコンソールに出力できますが、単純なノンブロッキング ライブラリ呼び出しによってロックされています。
#5 の攻撃的な呼び出しは関数 unicode.encode であり、これはノンブロッキングでなければなりません。スレッドがロックする位置のスレッド 1 の次のコードは、(予想どおり) 'A' と 'B' を出力します。
print('A')
print('B')
ただし、次の例では「A」のみが出力され、スレッドがブロックされます。
print('A')
u'hello'.encode('utf8') # This dummy (non-blocking) call locks up Thread 1
print('B')
これは私にはまったく意味がありません。2 つのスレッド間に論理的なデッドロック状態はありません。スレッド 1 は、RLock の取得を黙って待機しているスレッド 2 にまったく干渉しないノンブロッキング ライブラリ呼び出しによってブロックされています。スレッド 1 がブロックされている唯一の原因は、スレッド 1 が GIL を待っていることです。
これをさらにトラブルシューティングする方法、または回避策として GIL 操作を制御または操作するメカニズムはありますか?
編集: samplebias に対応する追加情報 (および返信ありがとうございます)。この問題は、2 つのスレッド間のタイミングを乱す可能性のあるものに非常に敏感であるように思われるため、トレースの取得に問題がありました。ただし、-f オプションのみを指定して strace を実行すると、数回繰り返した後、トレースを取得できました。
スレッド 1 には、「CHECK_IN」と「CHECK_TEST」の 2 行をコンソールに出力する必要がある次の 3 つのデバッグ ステートメントが含まれています。
print('CHECK IN')#DEBUG
u'hello'.encode('utf8')
print('CHECK TEST')#DEBUG
strace の最後のページは次のとおりです。
8605 mmap2(NULL, 266240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb753d000
8605 mmap2(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xb6d3c000
8605 mprotect(0xb6d3c000, 4096, PROT_NONE) = 0
8605 clone(child_stack=0xb753c494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb753cbd8, {entry_number:6, base_addr:0xb753cb70, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb753cbd8) = 8606
8606 set_robust_list(0xb753cbe0, 0xc <unfinished ...>
8605 futex(0xa239138, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... set_robust_list resumed> ) = 0
8606 futex(0xa239138, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 gettimeofday( <unfinished ...>
8605 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... gettimeofday resumed> {1301528807, 326496}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605 gettimeofday( <unfinished ...>
8606 <... futex resumed> ) = 0
8605 <... gettimeofday resumed> {1301528807, 326821}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8605 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8606 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
8605 <... futex resumed> ) = 0
8606 gettimeofday( <unfinished ...>
8605 futex(0xa272398, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... gettimeofday resumed> {1301528807, 326908}, NULL) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1) = 1
8605 <... futex resumed> ) = 0
8606 futex(0xa272398, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
8605 futex(0xa1b0d70, FUTEX_WAIT_PRIVATE, 0, NULL <unfinished ...>
8606 <... futex resumed> ) = 0
8606 stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=2225, ...}) = 0
8606 fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
8606 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb6d3b000
8606 write(1, "CHECK IN\n", 9) = 9
8606 futex(0xa115270, FUTEX_WAIT_PRIVATE, 0, NULL
プログラムがロックする前の 3 行のコードの出力は、次のとおりです。
CHECK IN
したがって、strace は、スレッド 1 (#8606) が 'CHECK_IN' 文字列を書き込む方法を示しており、unicode.encode 呼び出しに到達すると、決して返されない待機状態になります。
ところで、私はすべてのモジュールでいくつかの将来のインポートを作成して、いくつかの新しい Python 規則を維持しています ...
from __future__ import print_function, unicode_literals
...しかし、特にu'hello'文字列がUnicode文字列として明示的に呼び出されているため、それらが違いを生むはずがありません。