`
san_yun
  • 浏览: 2654993 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

进程无法退出总结

 
阅读更多

问题记录:
jython 运行某个脚本不会退出,通过jstack发现主线程等在Thread.join()上:

"MainThread" prio=10 tid=0x000000005891a000 nid=0x7d6d in Object.wait() [0x0000000041f5d000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000f7c50b18> (a org.python.core.FunctionThread)
    at java.lang.Thread.join(Thread.java:1186)
    - locked <0x00000000f7c50b18> (a org.python.core.FunctionThread)
    at java.lang.Thread.join(Thread.java:1239)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:186)
    at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204)
    at org.python.core.PyObject.__call__(PyObject.java:403)
    at org.python.core.PyObject.__call__(PyObject.java:407)
    at org.python.core.PyMethod.__call__(PyMethod.java:121)
    at threading$py.join$22(/duitang/dist/sys/jython/Lib/threading.py:126)
    at threading$py.call_function(/duitang/dist/sys/jython/Lib/threading.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:127)
    at org.python.core.PyFunction.__call__(PyFunction.java:347)
    at org.python.core.PyMethod.__call__(PyMethod.java:121)
    at threading$py._MainThread__exitfunc$40(/duitang/dist/sys/jython/Lib/threading.py:252)
    at threading$py.call_function(/duitang/dist/sys/jython/Lib/threading.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:194)
    at org.python.core.PyFunction.__call__(PyFunction.java:417)
    at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:232)
    at org.python.core.PyMethod.__call__(PyMethod.java:223)
    at org.python.core.PyMethod.__call__(PyMethod.java:218)
    at org.python.core.PyObject._callextra(PyObject.java:543)
    at atexit$py._run_exitfuncs$1(/duitang/dist/sys/jython/Lib/atexit.py:34)
    at atexit$py.call_function(/duitang/dist/sys/jython/Lib/atexit.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:120)
    at org.python.core.PyFunction.__call__(PyFunction.java:337)
    at org.python.core.PyFunction.__call__(PyFunction.java:332)
    at org.python.core.PySystemState.callExitFunc(PySystemState.java:555)
    at org.python.util.PythonInterpreter.cleanup(PythonInterpreter.java:344)
    at org.python.util.jython.run(jython.java:383)
    at org.python.util.jython.main(jython.java:137)

查看thread代码发现,进程退出的时候会通过atexit触发__exitfunc,内部实现就是等待所有非Daemon执行完毕。

class _MainThread(Thread):
    def __init__(self):
        Thread.__init__(self, name="MainThread")
        import atexit
        atexit.register(self.__exitfunc)

    def _create_thread(self):
        return java.lang.Thread.currentThread()

    def _set_daemon(self):
        return False

    def __exitfunc(self):
        _unregister_thread(self._thread)
        t = _pickSomeNonDaemonThread()
        while t:
            t.join()
            t = _pickSomeNonDaemonThread()

 
通过代码定位发现是stomp启动时会启动一个线程开启read_loop,代码如下:

def start(self):
    """
    Start the connection. This should be called after all
    listeners have been registered. If this method is not called,
    no frames will be received by the connection.
    """
    self.__running = True
    self.__attempt_connection()
    thread = self.create_thread_fc(self.__receiver_loop)
    self.__notify('connecting')

通过jstack也可以看到:
"Thread-1" prio=10 tid=0x00000000589e8800 nid=0x7d8f runnable [0x0000000041638000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.FileDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:21)
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:198)
    at sun.nio.ch.IOUtil.read(IOUtil.java:171)
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:243)
    - locked <0x00000000f7c43b30> (a java.lang.Object)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:186)
    at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:204)
    at org.python.core.PyObject.__call__(PyObject.java:420)
    at org.python.core.PyObject.__call__(PyObject.java:424)
    at org.python.core.PyMethod.__call__(PyMethod.java:136)
    at socket$py._do_read_nio$49(/duitang/dist/sys/jython/Lib/socket.py:471)
    at socket$py.call_function(/duitang/dist/sys/jython/Lib/socket.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:149)
    at org.python.core.PyFunction.__call__(PyFunction.java:357)
    at org.python.core.PyMethod.__call__(PyMethod.java:136)
    at socket$py.read$52(/duitang/dist/sys/jython/Lib/socket.py:486)
    at socket$py.call_function(/duitang/dist/sys/jython/Lib/socket.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:149)
    at org.python.core.PyFunction.__call__(PyFunction.java:357)
    at org.python.core.PyMethod.__call__(PyMethod.java:136)
    at socket$py.recv$153(/duitang/dist/sys/jython/Lib/socket.py:1327)
    at socket$py.call_function(/duitang/dist/sys/jython/Lib/socket.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
    at org.python.core.PyFunction.function___call__(PyFunction.java:406)
    at org.python.core.PyFunction.__call__(PyFunction.java:401)
    at org.python.core.PyFunction.__call__(PyFunction.java:396)
    at org.python.core.PyObject._callextra(PyObject.java:543)
    at socket$py.map_exception$27(/duitang/dist/sys/jython/Lib/socket.py:171)
    at socket$py.call_function(/duitang/dist/sys/jython/Lib/socket.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
    at org.python.core.PyFunction.function___call__(PyFunction.java:406)
    at org.python.core.PyFunction.__call__(PyFunction.java:401)
    at org.python.core.PyFunction.__call__(PyFunction.java:396)
    at org.python.core.PyObject._callextra(PyObject.java:543)
    at socket$py.set_last_error$29(/duitang/dist/sys/jython/Lib/socket.py:183)
    at socket$py.call_function(/duitang/dist/sys/jython/Lib/socket.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:301)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:141)
    at org.python.core.PyFunction.__call__(PyFunction.java:357)
    at org.python.core.PyMethod.__call__(PyMethod.java:136)
    at stomp.connect$py._Connection__read$30(/duitang/dist/app/main/java/japa/src/main/webapp/stomp/connect.py:851)
    at stomp.connect$py.call_function(/duitang/dist/app/main/java/japa/src/main/webapp/stomp/connect.py)
    at org.python.core.PyTableCode.call(PyTableCode.java:165)
    at org.python.core.PyBaseCode.call(PyBaseCode.java:134)
    at org.python.core.PyFunction.__call__(PyFunction.java:347)
    at org.python.core.PyMethod.__call__(PyMethod.java:121)
    at stomp.connect$py._Connection__receiver_loop$28(/duitang/dist/app/main/java/japa/src/main/webapp/stomp/connect.py:756)
    at stomp.connect$py.call_function(/duitang/dist/app/main/java/japa/src/main/webapp/stomp/connect.py)

改进措施:
mqclient新增一个atexit.register(mqclient.stop)

总结:
1. 后台线程需要管理好自己的生命周期,提供stop接口
2. 线程应该daemon还是非daemon需要考虑一下,一般不可打断的线程应该设计为非daemon的,通过exit钩子退出。

 

分享到:
评论

相关推荐

    检测子进程退出的方法

    总结来说,处理子进程退出的关键在于理解进程间通信机制,尤其是信号和`waitpid`函数的使用。在编写多进程程序时,正确处理子进程的生命周期能确保系统的稳定性和数据一致性。同时,这也是系统级编程中不可或缺的...

    vb/vba引用excel无法退出excel进程的解决方法

    ### vb/vba引用excel无法退出excel进程的解决方法 在使用VB/VBA编程语言操作Excel时,经常会遇到一个令人头疼的问题:尽管已经执行了`xlapp.Quit` 和 `Set xlapp = Nothing`来关闭Excel应用并释放相关资源,但Excel...

    进程退出控制exit

    总结来说,`exit()`是最常用的进程退出方式,因为它提供了完整的清理功能;`_exit()`则用于避免清理过程,适用于特殊需求;而主函数中的`return`则是一种简洁的退出方式,适用于简单的程序结构。在编写程序时,根据...

    进程管理与通信总结

    - 调用`fork()`创建子进程,并让父进程退出。 - 子进程中调用`setsid()`创建新的会话,脱离原有终端。 - 改变当前工作目录为根目录。 - 设置文件权限掩码为0,以便进程可以自由地创建文件。 - 关闭所有不必要的...

    进程编程总结

    在这个总结中,我们将深入探讨进程的性质、编程技巧以及进程的退出机制,这些都是初学者在学习多任务处理时必须掌握的基础知识。 首先,我们要理解什么是进程。进程是计算机中运行的程序的一个实例,它包括程序代码...

    进程创建、进程退出、注册表1

    本文将深入探讨进程的创建、进程退出以及注册表操作的相关知识。 首先,我们来看进程的创建。在Windows API中,`CreateProcess`函数是用于创建新进程的主要方法。这个函数接收多个参数,包括要执行的应用程序名称、...

    Linux进程项目个人总结PPT优秀资料.ppt

    原来的方法是不释放资源的,使得程序退出后资源无法释放。我们改进了方法,在程序退出时销毁共享内存和信号量集,从而释放资源。 三、对软件开发的基本流程的了解 通过完成这个项目,我对软件开发的基本流程有了...

    进程通讯总结及测试

    需要注意的是,进程退出时,与其挂接的共享内存不会自动删除,需要手动调用`shmdt()`来卸载。此外,当父进程创建了共享内存,子进程会继承这些共享内存。如果共享内存被标记为删除,且挂接数为0,内核会自动清理这个...

    pb9.0 pb11.5 强制结束进程 可支持多个同名进程强杀

    总结起来,"pb9.0 pb11.5 强制结束进程 可支持多个同名进程强杀"涉及到的是Progress OpenEdge环境下,如何在不同版本中高效且安全地结束同名进程的技巧和策略,包括使用工具、编写脚本以及了解版本差异等。...

    解决U盘无法正常退出的方法

    ### 解决U盘无法正常退出的方法 在使用Windows XP系统的过程中,用户经常会遇到U盘无法正常退出的问题。当试图安全删除U盘时,系统可能会弹出提示“现在无法停止‘通用卷’设备,请稍候再停止该设备”。这不仅让人...

    进程操作 关闭进程 进程ID

    总结来说,VC++开发中,进程操作是系统编程的重要部分,涉及到枚举系统中运行的进程、关闭指定进程以及使用进程ID进行各种操作。通过学习和熟练掌握这些技术,开发者可以更好地控制和管理应用程序与其他进程的交互。...

    c++实现进程的终止

    这个函数需要进程句柄和退出码。以下是C++中使用`TerminateProcess`的示例: ```cpp #include BOOL terminateProcess(HANDLE processHandle, DWORD exitCode) { return TerminateProcess(processHandle, exit...

    Linux进程学习总结.docx

    `wait()`会阻塞父进程,直到任何子进程终止,返回子进程的退出状态。`waitpid()`更灵活,允许指定要等待的特定子进程ID,并且可以设置等待选项。 最后,孤儿进程和守护进程是两种特殊类型的进程。孤儿进程是其父...

    多进程共享临界资源

    当有进程退出临界区时,管理进程检查队列中的下一个进程,并允许其进入临界区。 #### 3. 访问准则 - **空闲让进**:如果临界区为空闲状态,则任何进程都可以进入。 - **忙则等待**:如果有进程正在临界区内,则...

    python编写守护进程实现当python进程被杀后重启进程的源代码

    # 第一次fork,创建子进程,父进程退出 pid = os.fork() if pid &gt; 0: sys.exit(0) # 父进程退出 except OSError as e: sys.stderr.write(f"fork failed: {e}\n") sys.exit(1) # 终端分离,改变工作目录,...

    Linux进程学习总结.pdf

    - `exit()`和 `_exit()`用于进程退出,但`exit()`会执行清理工作,如执行析构函数和释放文件描述符。 - `wait()`和`waitpid()`函数用于父进程等待子进程结束,回收子进程资源。 8. **进程控制函数`exec()`系列**...

    进程监视进程守护

    在本场景中,"进程监视器"是一款工具,它能够监控特定的进程,一旦发现该进程失去响应或者意外退出,它会自动重启这个进程,并且能模拟用户操作,比如点击指定的按钮或输入特定的文本,以确保进程能够完整启动。...

    vb写的结束指定进程

    总结来说,VB提供的`Process`类使得开发者能够轻松地进行进程管理,包括查找、监控和结束进程。"vb写的结束指定进程"这个程序就是一个很好的实践案例,展示了如何利用这些功能实现实用的进程管理工具。在编程时,...

    lab2 进程与线程1

    3. **退出进程**:函数让当前进程退出,关闭所有文件,取消对节点的引用,唤醒父进程,并将子进程的父进程更改为初始进程。进程状态变为"已退出",调度程序会处理进程的退出。 4. **等待子进程**:函数用于父进程...

    死任务管理器无法结束的进程

    总结一下,当我们遇到任务管理器无法结束的进程时,可以尝试使用ntsd命令。创建批处理文件可以简化这一操作,但需谨慎对待,避免对系统造成负面影响。通过深入理解这些工具和命令,我们可以更有效地管理和维护我们的...

Global site tag (gtag.js) - Google Analytics