C++和 Python 混合编程时 Python 创建的子线程不会运行的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zhiqiang
V2EX    Python

C++和 Python 混合编程时 Python 创建的子线程不会运行的问题

  •  1
     
  •   zhiqiang 2017-08-17 17:28:27 +08:00 4625 次点击
    这是一个创建于 2979 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设一个 Python 程序,内部有一个子线程。那么 C++调用该程序时,子线程不会自动运行。只有 C++在调用 Python 程序时,该子线程才会随之运行一小段时间。

    示例 Python 程序 test_python_thread.py如下,调用的 c++代码test_python_thread.cpp附在后面。编译后直接运行./test_python_thread无输出,输入xxx后输出十个数字后停止。但按道理,python 代码应该会每秒钟输出一个数字。

    我想知道怎么才能让 Python 里面的子线程能够不间断运行(每秒钟输出 1 个数字)?

    #!/usr/bin/env python # encoding: utf-8 import thread, time class PyTest: def __init__(self): def local_python_thread(s): while True: print "local_python_thread", s s += 1 time.sleep(1) thread.start_new_thread(local_python_thread, (0, )) def xxx(self): s = 0 while s < 10: print "cpp_thread", s s += 1 time.sleep(1) 

    示例 C++程序 (test_python_thread.cpp

    #include <python2.7/Python.h> #include <boost/python.hpp> #include <boost/filesystem.hpp> #include <iostream> #include <thread> namespace bp = boost::python; class CppTest { private: bp::object python_module; bp::object python_class; bp::object python_object; bp::object python_xxx; public: CppTest() { Py_Initialize(); // 初始化 PyRun_SimpleString("import sys"); boost::filesystem::path path = "./test_python_thread.py"; std::string chdir_cmd = std::string("sys.path.append(\"") + path.parent_path().c_str() + "\")"; PyRun_SimpleString("sys.path.append('./')"); PyRun_SimpleString(chdir_cmd.c_str()); python_module = bp::import(path.stem().c_str()); python_class = python_module.attr("PyTest"); python_object = python_class(); python_xxx = python_object.attr("xxx"); } virtual void xxx() { python_xxx(); } }; int main() { CppTest test{}; std::string cmd; while (true) { std::getline(std::cin, cmd); if (cmd == "xxx") { test.xxx(); } } return 0; } 

    编译 cpp(需要 boost 库):

    g++ -std=c++0x -o test_python_thread test_python_thread.cpp -lboost_system -l boost_filesystem -l python2.7 -g -I /usr/include/python2.7/ -l boost_python 
    13 条回复    2017-08-18 08:43:43 +08:00
    hl
        1
    hl  
       2017-08-17 18:27:44 +08:00
    每太看懂啥意思,不知道是不是因为没有 join 线程的问题导致的.
    albertofwb
        2
    albertofwb  
       2017-08-17 18:38:44 +08:00 via Android
    主进程退出之后,其所创建的所有子线程也会退出。python 创建子线程的时候,有一个属性里设置好之后,可以防止这个。好像是 SetDaemon(True) 这个属性。
    dbow
        3
    dbow  
       2017-08-17 18:49:12 +08:00
    主线程退出 ,daemon thread 也会退出 , 换成下面的方式试试。
    t = threading.Thread(target=local_python_thread, args=(0, ))
    t.start()
    ->
    daemon
    A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.
    takeoffyoung
        4
    takeoffyoung  
       2017-08-17 18:57:52 +08:00
    thread 已经是 deprecated 了
    推荐的做法是,创建一个继承自 threading.Thread 的类的实例 obj.(需要实现 run()函数)
    然后 obj.setDaemon(True); obj.start();
    while threading.active() > 0:
    pass
    保证主进程不退出,后台线程得以正确运行
    wangxn
        5
    wangxn  
       2017-08-17 19:39:09 +08:00 via Android
    那个创建的线程直接被回收了吧……连引用都没。
    zhiqiang
        6
    zhiqiang  
    OP
       2017-08-17 20:39:51 +08:00 via Android
    @albertofwb @dbow 主进程没有退出,一直在 getline 等待用户输入。
    zhiqiang
        7
    zhiqiang  
    OP
       2017-08-17 20:42:05 +08:00 via Android
    那个线程一直还在,只是没有运行。

    每次输入 xxx 后会该线程会运行输出 10 个数。
    zhouheyang0919
        8
    zhouheyang0919  
       2017-08-17 20:46:04 +08:00   1
    @zhiqiang

    C++ 代码没有调用 Python 解释器时,应该显式释放 GIL 来允许 Python 代码执行。

    调用进 Python 代码前,应重新锁定 GIL。
    zhouheyang0919
        9
    zhouheyang0919  
       2017-08-17 20:48:06 +08:00
    @zhiqiang

    关键词 PyGILState
    ysc3839
        10
    ysc3839  
       2017-08-17 22:12:46 +08:00
    @zhouheyang0919
    这里有个说明:
    https://docs.python.org/3/c-api/init.html#releasing-the-gil-from-extension-code
    大概是说,你的程序在执行耗时操作,同时不调用 Python 的话这样写代码:
    Py_BEGIN_ALLOW_THREADS
    ... Do some blocking I/O operation ...
    Py_END_ALLOW_THREADS
    可以让 Python 的线程并行运行。
    ysc3839
        11
    ysc3839  
       2017-08-17 22:14:54 +08:00
    zhiqiang
        12
    zhiqiang  
    OP
       2017-08-18 08:22:41 +08:00
    谢谢 @ysc3839 @zhouheyang0919 点到位了。我面临的情况比示例要复杂,C++和 Python 里都有多线程,而且互相调用。我先去尝试一下,有问题再请教。
    ysc3839
        13
    ysc3839  
       2017-08-18 08:43:43 +08:00 via Android
    @zhiqiang 前面 Python Docs 里也有说 C++ 多线程该怎么做。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1239 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 23:34 PVG 07:34 LAX 16:34 JFK 19:34/a>
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86