使用子进程,pty和线程池的死锁

安东尼·索特蒂尔

我有,我想假一TTY连接至在一个子进程运行在特定情况下ThreadPoolExecutor(这样想xargs -p),并捕获输出。

我创建了以下内容,这些内容似乎可以连续工作:

import contextlib
import concurrent.futures
import errno
import os
import subprocess
import termios


@contextlib.contextmanager
def pty():
    r, w = os.openpty()
    try:
        yield r, w
    finally:
        for fd in r, w:
            try:
                os.close(fd)
            except OSError:
                pass


def cmd_output_p(*cmd):
    with pty() as (r, w):
        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=w, stderr=w)
        os.close(w)
        proc.stdin.close()

        buf = b''
        while True:
            try:
                bts = os.read(r, 1024)
            except OSError as e:
                if e.errno == errno.EIO:
                    bts = b''
                else:
                    raise
            else:
                buf += bts
            if not bts:
                break

    return proc.wait(), buf

和一些示例用法:

>>> cmd_output_p('python', '-c', 'import sys; print(sys.stdout.isatty())')
(0, b'True\r\n')

太棒了!但是,当我在相同的过程中运行时,concurrent.futures.ThreadPoolExecutor会有很多故障模式(还有另外一种较为罕见的故障模式,即OSError: [Errno 9] Bad file descriptor在看似随机的代码行上发生的代码-但我还没有隔离该代码的复制品)

例如以下代码:

def run(arg):
    print(cmd_output_p('echo', arg))


with concurrent.futures.ThreadPoolExecutor(5) as exe:
    exe.map(run, ('1',) * 1000)

这会经过一系列过程,然后最终挂起。发出^C以下堆栈跟踪(需要两次^ C才能结束进程)

$ python3 t.py
...

(0, b'1\r\n')
(0, b'1\r\n')
(0, b'1\r\n')
^CTraceback (most recent call last):
  File "t.py", line 49, in <module>
    exe.map(run, ('1',) * 1000)
  File "/usr/lib/python3.6/concurrent/futures/_base.py", line 611, in __exit__
    self.shutdown(wait=True)
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 152, in shutdown
    t.join()
  File "/usr/lib/python3.6/threading.py", line 1056, in join
    self._wait_for_tstate_lock()
  File "/usr/lib/python3.6/threading.py", line 1072, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt
^CError in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 40, in _python_exit
    t.join()
  File "/usr/lib/python3.6/threading.py", line 1056, in join
    self._wait_for_tstate_lock()
  File "/usr/lib/python3.6/threading.py", line 1072, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt

大概我做错了什么,但是我发现与子流程/ pty交互的所有示例都执行相同的步骤-如何防止这种死锁?

戴维斯鲱鱼

打开因为文件描述符w由一个线程可以通过调用之间的另一个线程被重用os.closecmd_output_p和那个在pty在这种情况下,它会在第二秒之前意外关闭close(否则将对造成“无害”失败EBADF)。(在几乎所有多线程程序中,都EBADF必须将其视为断言失败。)

那肯定会导致EBADF来自另一个线程。如果重新打开文件描述符,则可能会导致死锁,因为伪终端的两端都是可读写的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用使用Django网站中的线程和子进程的库

来自分类Dev

python子进程死锁

来自分类Dev

如何使用自己的线程池和其他配置独立运行两个进程?

来自分类Dev

自动终止进程和多处理池的子进程

来自分类Dev

自动终止进程和多处理池的子进程

来自分类Dev

线程死锁和同步

来自分类Dev

线程池死锁:针对或检测设计

来自分类Dev

使用Boost线程和io_service创建线程池

来自分类Dev

使用JavaFX Tasks正确执行多线程和线程池

来自分类Dev

Java-何时使用固定大小的线程池和可变大小的线程池?

来自分类Dev

Java-何时使用固定大小的线程池和可变大小的线程池?

来自分类Dev

异步使用线程池?

来自分类Dev

为什么此线程池死锁或运行太多次?

来自分类Dev

使用池和映射功能进行线程化

来自分类Dev

异步任务和线程池执行器的使用

来自分类Dev

播放框架和线程池

来自分类Dev

模块,进程和线程?

来自分类Dev

使用管道与多线程程序中的子进程进行通信

来自分类Dev

线程,线程池和Unity的ThreadScope

来自分类Dev

线程池和对象的线程问题

来自分类Dev

WPF同步动画和UI线程死锁

来自分类Dev

Java线程和HTTP请求死锁

来自分类Dev

如何使用windbg调试子进程和父进程?

来自分类Dev

Linux中的Python:使用Shell杀死进程和子进程

来自分类Dev

如何减少Linux上一个进程的所有线程(和子进程)?

来自分类Dev

如何减少Linux上一个进程的所有线程(和子进程)?

来自分类Dev

使用 Executor Framrwork 的线程池

来自分类Dev

这个Ruby代码是否正确使用了线程,线程池和并发性

来自分类Dev

线程池未按预期使用线程?

Related 相关文章

热门标签

归档