2016-10-05 15 views
1

コンテキスト多量原因デッドロック

私はmultiprocessing.ThreadPool内部multiprocessing.Processを実行する必要があります。 最初は不思議そうですが、これは、私がC++共有ライブラリを使用しているために発生する可能性のあるsegfaultを扱う唯一の方法です。 segfaultが追加された場合、そのプロセスは強制終了され、process.exitcodeをチェックしてそれを処理できます。

問題

しばらくして、私はプロセスに参加しようとしていたときに、デッドロックが追加。

import sys, time, multiprocessing 
from multiprocessing.pool import ThreadPool 

def main(): 
    # Launch 8 workers 
    pool = ThreadPool(8) 
    it = pool.imap(run, range(500)) 
    while True: 
     try: 
      it.next() 
     except StopIteration: 
      break 

def run(value): 
    # Each worker launch it own Process 
    process = multiprocessing.Process(target=run_and_might_segfault,  args=(value,)) 
    process.start() 

    while process.is_alive(): 
     sys.stdout.write('.') 
     sys.stdout.flush() 
     time.sleep(0.1) 

    # Will never join after a while, because of a mystery deadlock 
    process.join() 

    # Deals with process.exitcode to log errors 

def run_and_might_segfault(value): 
    # Load a shared library and do stuff (could throw c++ exception, segfault ...) 
    print(value) 

if __name__ == '__main__': 
    main() 

そして、ここでは、可能な出力である:ここで

は簡易版私のコードであるあなたが見ることができるように

➜ ~ python m.py 
..0 
1 
........8 
.9 
.......10 
......11 
........12 
13 
........14 
........16 
........................................................................................ 

process.is_alive()は数回の反復後なかれ真である、プロセスは意志参加しないでください。

I CTRL-Cスクリプトこのスタックトレースを取得する場合:MacOSの上のpython 3.5.2を使用して

Traceback (most recent call last): 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/multiprocessing/pool.py", line 680, in next 
    item = self._items.popleft() 
IndexError: pop from an empty deque 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "m.py", line 30, in <module> 
    main() 
    File "m.py", line 9, in main 
    it.next() 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/multiprocessing/pool.py", line 684, in next 
    self._cond.wait(timeout) 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/threading.py", line 293, in wait 
    waiter.acquire() 
KeyboardInterrupt 

Error in atexit._run_exitfuncs: 
Traceback (most recent call last): 
    File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5 /lib/python3.5/multiprocessing/popen_fork.py", line 29, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
KeyboardInterrupt 

PS

ご協力いただきありがとうございます。

編集

私は、Python 2.7を使用してみました、それがうまく機能しています。 Python 3.5の問題のみである可能性がありますか?

答えて

4

この問題は、CPythonの最新ビルド - Python 3.7.0a0 (default:4e2cce65e522, Oct 13 2016, 21:55:44)でも再現されています。

あなたはgdbで停止しているプロセスの一つにattach、あなたはsys.stdout.flush()コールでロックを取得しようとしていることがわかります場合:

(gdb) py-list 
263    import traceback 
264    sys.stderr.write('Process %s:\n' % self.name) 
265    traceback.print_exc() 
266   finally: 
267    util.info('process exiting with exitcode %d' % exitcode) 
>268    sys.stdout.flush() 
269    sys.stderr.flush() 
270 
271   return exitcode 

Pythonのレベルのバックトレースは次のようになります。

(gdb) py-bt 
Traceback (most recent call first): 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/process.py", line 268, in _bootstrap 
    sys.stdout.flush() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/popen_fork.py", line 74, in _launch 
    code = process_obj._bootstrap() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/popen_fork.py", line 20, in __init__ 
    self._launch(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/context.py", line 277, in _Popen 
    return Popen(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/context.py", line 223, in _Popen 
    return _default_context.get_context().Process._Popen(process_obj) 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/process.py", line 105, in start 
    self._popen = self._Popen(self) 
    File "deadlock.py", line 17, in run 
    process.start() 
    File "/home/rpodolyaka/src/cpython/Lib/multiprocessing/pool.py", line 119, in worker 
    result = (True, func(*args, **kwds)) 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 864, in run 
    self._target(*self._args, **self._kwargs) 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 916, in _bootstrap_inner 
    self.run() 
    File "/home/rpodolyaka/src/cpython/Lib/threading.py", line 884, in _bootstrap 
    self._bootstrap_inner() 

(gdb) frame 6 

(gdb) list 
287  return 0; 
288 } 
289 relax_locking = (_Py_Finalizing != NULL); 
290 Py_BEGIN_ALLOW_THREADS 
291 if (!relax_locking) 
292  st = PyThread_acquire_lock(self->lock, 1); 
293 else { 
294  /* When finalizing, we don't want a deadlock to happen with daemon 
295   * threads abruptly shut down while they owned the lock. 
296   * Therefore, only wait for a grace period (1 s.). ... */ 

(gdb) p /x self->lock 
$1 = 0xd25ce0 

(gdb) p /x self->owner 
$2 = 0x7f9bb2128700 

注:それはのように見えるインタプリタレベルで

、それはロックがまだ親プロセス内のスレッドの1(LWP 1105)によって所有され、この特定の子プロセスの視点から:

(gdb) info threads 
    Id Target Id   Frame 
* 1 Thread 0x7f9bb5559440 (LWP 1102) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0xe4d340) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 
    2 Thread 0x7f9bb312a700 (LWP 1103) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    3 Thread 0x7f9bb2929700 (LWP 1104) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    4 Thread 0x7f9bb2128700 (LWP 1105) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    5 Thread 0x7f9bb1927700 (LWP 1106) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    6 Thread 0x7f9bb1126700 (LWP 1107) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    7 Thread 0x7f9bb0925700 (LWP 1108) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    8 Thread 0x7f9b9bfff700 (LWP 1109) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    9 Thread 0x7f9b9b7fe700 (LWP 1110) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    10 Thread 0x7f9b9affd700 (LWP 1111) "python" 0x00007f9bb4780253 in select() at ../sysdeps/unix/syscall-template.S:84 
    11 Thread 0x7f9b9a7fc700 (LWP 1112) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0x7f9b80001ed0) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 
    12 Thread 0x7f9b99ffb700 (LWP 1113) "python" 0x00007f9bb5157577 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, 
    futex_word=0x7f9b84001bb0) at ../sysdeps/unix/sysv/linux/futex-internal.h:205 

だから、確かにデッドロックだとそれが原因事実に起こりますその​​システムコール の性質によって、子プロセスを作成しながら、元のプロセスで複数の スレッドで同時に書き込みとフラッシュを実行します。fork()ロックが取得されている間にコールが実行されている必要があります。親プロセスが最終的にそれを解放したとしても、子プロセスはそれ自身のメモリ空間を持つようになります。書き込み時にコピーされます。

したがって、あなたは、マルチプロセッシングと マルチスレッドを混合する際に非常に気をつけて、それらが に子プロセスで使用されている場合、すべてのロックが適切にfork()前にリリースされていることを確認する必要があります。

それはあなたのスニペットからsys.stdoutとの相互作用を削除すると、それが正常に動作すること、http://bugs.python.org/issue6721

ノートに記載されているものと非常によく似ています。

関連する問題