MCDReforged / MCDReforged

A rewritten version of MCDaemon, a python tool to control your Minecraft server
https://mcdreforged.com
GNU Lesser General Public License v3.0
910 stars 77 forks source link

关服提示线程相关错误 #47

Closed AnzhiZhang closed 1 year ago

AnzhiZhang commented 4 years ago
Fatal Python error: could not acquire lock for <_io.BufferedReader name='<stdin>'> at interpreter shutdown, possibly due to daemon threads
>Python runtime state: finalizing (tstate=01059B00)

Thread 0x00000fbc (most recent call first):
>  File "D:\Program Files\Python38-32\lib\threading.py", line 306 in wait
>  File "D:\Program Files\Python38-32\lib\queue.py", line 179 in get
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\server.py", line 352 in info_react
>  File "D:\Program Files\Python38-32\lib\threading.py", line 870 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x00004bc4 (most recent call first):
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\server.py", line 321 in console_input
>  File "D:\Program Files\Python38-32\lib\threading.py", line 870 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x000049e8 (most recent call first):
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\update_helper.py", line 23 in check_update_loop
>  File "D:\Program Files\Python38-32\lib\threading.py", line 870 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x000045ac (most recent call first):
>  File "D:\Program Files\Python38-32\lib\threading.py", line 306 in wait
>  File "D:\Program Files\Python38-32\lib\queue.py", line 179 in get
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\plugin_thread.py", line 33 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x00004038 (most recent call first):
>  File "D:\Program Files\Python38-32\lib\threading.py", line 306 in wait
>  File "D:\Program Files\Python38-32\lib\queue.py", line 179 in get
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\plugin_thread.py", line 33 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x00003d7c (most recent call first):
>  File "D:\Program Files\Python38-32\lib\threading.py", line 306 in wait
>  File "D:\Program Files\Python38-32\lib\queue.py", line 179 in get
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\plugin_thread.py", line 33 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Thread 0x000033c4 (most recent call first):
>  File "D:\Program Files\Python38-32\lib\threading.py", line 306 in wait
>  File "D:\Program Files\Python38-32\lib\queue.py", line 179 in get
>  File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\plugin_thread.py", line 33 in run
>  File "D:\Program Files\Python38-32\lib\threading.py", line 932 in _bootstrap_inner
>  File "D:\Program Files\Python38-32\lib\threading.py", line 890 in _bootstrap

Current thread 0x000036c8 (most recent call first):
<no Python frame>

好几个版本直接就见过了,今天又见到了,似乎是插件线程管理问题 File "D:\Project\Python\MCSManager_8.6.11_Win_x86\server\server_core\DevServer\utils\plugin_thread.py", line 33 in run

Fallen-Breath commented 4 years ago

不是插件线程什么的问题,感觉更像是python自己处理deamon线程跟stdin的问题 然后,依旧,求稳定复现方法

AnzhiZhang commented 4 years ago

BUG.zip 我使用的整合,用常规的应该也可以 系统环境Win10 64, Python 3.8

复现方法:cmd运行正常,使用 PyCham运行 stop 关服时报错

联系MCSM同样报错猜测与MCDR被套娃有关

AnzhiZhang commented 4 years ago

完整控制台截图 image

dogdie233 commented 4 years ago

用C#窗体应用写了个套娃机,好像没有出现问题

源码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;

namespace test
{
    public partial class Form1 : Form
    {
        private Process process;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            process = new Process();
            process.StartInfo.UseShellExecute = false;   // 是否使用外壳程序
            process.StartInfo.CreateNoWindow = true;   //是否在新窗口中启动该进程的值
            process.StartInfo.RedirectStandardInput = true;  // 重定向输入流
            process.StartInfo.RedirectStandardOutput = true;  //重定向输出流
            process.StartInfo.RedirectStandardError = true;  //重定向错误流
            process.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
            process.Start();
            process.StandardInput.WriteLine("J:");
            process.StandardInput.WriteLine("cd J:/MCDReforged-0.6.3-alpha");
            process.StandardInput.WriteLine("python MCDReforged.py");
            backgroundWorker1.RunWorkerAsync();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            process.StandardInput.WriteLine(textBox1.Text);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            string str = process.StandardOutput.ReadLine();
            e.Result = str;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (process.HasExited == false)
            {
                backgroundWorker1.RunWorkerAsync();
                List<string> l = textBox2.Lines.ToList<string>();
                l.Add(e.Result as string);
                textBox2.Lines = l.ToArray();
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            process.Close();
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            textBox2.SelectionStart = textBox2.Text.Length;
            textBox2.ScrollToCaret();
        }
    }
}

可能是我套娃的方式不对?

输出

输出

AnzhiZhang commented 4 years ago

可能是我套娃的方式不对?

试试PyCharm和MCSManager

AnzhiZhang commented 4 years ago

关闭MCDR的控制台线程 disable_console_thread: true 也不会引发错误,参考报错信息 Fatal Python error: could not acquire lock for <_io.BufferedReader name='<stdin>'> at interpreter shutdown, possibly due to daemon threads 猜测是控制台输入的问题

Fallen-Breath commented 4 years ago

我知道出问题的地方在哪,我也会用pycharm,也没有遇到过此错误 无法 稳定 复现该问题,这也是该issue无法解决的原因

AnzhiZhang commented 4 years ago

文件太大发不上来,这里有一份http://tmp.link/f/5f45ddfa142e1,群文件里也有 请了两人使用该文件尝试,有一人成功复现,另一人没有,也许与系统环境有关系,可能需要更多人尝试复现并反馈 我的环境 Win10专业版 64, Python 3.8.3, MCDR0.9.5 CPU信息 image


方法 1.解压 2.运行start.bat 3.根据需要修改.\server\server_core\MCDR\start.bat用于启动MCDR 4.浏览器打开http://127.0.0.1:23333 5.账号 #master, 密码 123456 image 6.进入服务端管理 image 7.选择管理 image 8.选择命令控制台 image 9.开启MCDR image 10.启动完成后输入stop发送关闭服务器 image 11.关闭后就出现了 image


这两位的复现结果 image WSS5~@}O8MC6}`XOGJ2_A4Y

DancingSnow0517 commented 3 years ago

image 我也会报错,以前pycharm跑源码也会这个报错

Fallen-Breath commented 3 years ago

有可能是 MCDR 在退出时未终止输入线程的循环,导致继续尝试 input 所引发的,可以试一下 issue/47 分支的构建

https://github.com/Fallen-Breath/MCDReforged/actions/runs/1138028987

https://test.pypi.org/project/mcdreforged/1.6.2.dev244/

AnzhiZhang commented 3 years ago

有可能是 MCDR 在退出时未终止输入线程的循环,导致继续尝试 input 所引发的,可以试一下 issue/47 分支的构建

https://github.com/Fallen-Breath/MCDReforged/actions/runs/1138028987

https://test.pypi.org/project/mcdreforged/1.6.2.dev244/

使用action提供的构建,没有解决问题,但是报错似乎变了 image

上面截图是第一次启动的,下面是后续启动的报错

image

AnzhiZhang commented 3 years ago

我尝试了issue/47 分支的源码下载,也是报错 嗯对了最新版的源码也一样

shenjackyuanjie commented 2 years ago

是否跟这个issue有关系? https://bugs.python.org/issue26037

Fallen-Breath commented 1 year ago

是否跟这个issue有关系? https://bugs.python.org/issue26037

应该与这个 issue 是有关系的,即 https://github.com/python/cpython/issues/70225 。python 在 daemon 线程里读 stdin 就有可能出问题

对于 pycharm 下的出现问题,可以参考这个 issue:https://youtrack.jetbrains.com/issue/PY-43748

复现

代码

复现脚本:

# test_input.py
import sys
import threading
import time

threading.Thread(target=lambda: eval(sys.argv[1]), daemon=True).start()
time.sleep(0.1)

测试脚本:

# test_input_batch.py
import subprocess

methods = [
    'input()',
    'sys.stdin.readline()',
    'sys.stdin.buffer.readline()',
    'sys.stdin.buffer.raw.readline()',
]
for m in methods:
    print('======', m, '======')
    ret = subprocess.call('python test_input.py "{}"'.format(m), shell=True)
    print('====== ret', ret, '======')
    print()

简单套壳实现

# wrapper.py
import subprocess

proc = subprocess.Popen('python -u test_input_batch.py', universal_newlines=True, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    print(line, end='')

结果

在 Windows 10 + Python 3.9.12 + Pycharm 2023.1.2 下测试:

环境 input() sys.stdin.readline() sys.stdin.buffer.readline() sys.stdin.buffer.raw.readline()
pycharm, 直接运行 出错 正常 出错 正常
pycharm, emulate terminal 正常 正常 出错 正常
cmd 正常 正常 出错 正常
powershell 正常 正常 出错 正常
python wrapper.py 出错 正常 出错 正常

其中直接运行 pycharm、运行 python wrapper.py 的输出如下

====== input() ======
Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedReader name='<stdin>'> at interpreter shutdown, possibly due to daemon threads
Python runtime state: finalizing (tstate=000001B521D70FF0)

Current thread 0x00006e24 (most recent call first):
<no Python frame>
====== ret 3221225477 ======

====== sys.stdin.readline() ======
====== ret 0 ======

====== sys.stdin.buffer.readline() ======
Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedReader name='<stdin>'> at interpreter shutdown, possibly due to daemon threads
Python runtime state: finalizing (tstate=000001CA73D20780)

Current thread 0x00007f04 (most recent call first):
<no Python frame>
====== ret 3221225477 ======

====== sys.stdin.buffer.raw.readline() ======
====== ret 0 ======

总结

不同从 stdin 读取的方式可能会有不一样的表现,这应该是有 cpython 底层实现的差异导致的

如果 MCDR 的输入输出流被接管(如 pycharm 直接运行、其他程序套壳运行),input() 的表现可能会发生变化,并有可能导致该 issue 发生

可以考虑用 sys.stdin.readline() 替代 console_handler.py 里在 daemon 线程调用的 input()

https://github.com/Fallen-Breath/MCDReforged/blob/622b7173ee21b8164b57e28116d572d7eacc6376/mcdreforged/executor/console_handler.py#L303-L313

猜测

启用 advanced_console 后,不再有直接读 stdin 的操作,可能会抑制该 issue?不过在 MCDR 的输入输出流被接管的前提下,advanced_console 是得关掉的

Fallen-Breath commented 1 year ago

已在 issue/47 分支 https://github.com/Fallen-Breath/MCDReforged/commit/58ecfbce99fd5a84992f40cc8c4681a41fdd2590 中应用了 https://github.com/Fallen-Breath/MCDReforged/issues/47#issuecomment-1651128026 的猜测尝试,可以试试 https://test.pypi.org/project/mcdreforged/2.10.2.dev581/ 是否还会出现此问题