multiprocessing.Process() with method fork() works not the same with os.fork() on unloading of .so files
未關閉
還沒有人認領這個 Issue。
stdlib
topic-multiprocessing
type-bug
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 36k
- PR 合併指標
- PR 指標待擷取
描述
Bug report
Bug description:
I have a c/cpp file and compile it with pybind to get a so named xyz_test.cpython-311-x86_64-linux-gnu.so so that I can import it(xyz_test) and call a method named xyz_test.call() in Python code .
I use it with multiprocessing.Process() or os.fork(), but the unload process of this so is different:
with multiprocessing.setset_start_method('fork') and multiprocessing.Process(), this so is only unloaded while the parent process is terminated.
with os.fork(), this so is unloaded both while the child process and the parent process are terminated.
The behavior with os.fork() is the same with what I test on C code with C fork(), so is the behavior a bug with multiprocessing.Process() ?
Thank you!
# main_os_fork.py
import xyz_test
import os
import time
def func():
pid = os.getpid()
print(f'=== pid = {pid}, this is python func')
xyz_test.callTLS()
if __name__ == '__main__':
pid = os.getpid()
print(f'=== pid = {pid}, this is python main')
xyz_test.callTLS()
fork_pid = os.fork()
if fork_pid == 0:
func()
else:
time.sleep(1)
# main_mp_fork.py
import xyz_test
import multiprocessing
import os
import time
def func():
pid = os.getpid()
print(f'=== pid = {pid}, this is python func')
xyz_test.callTLS()
time.sleep(10*60)
if __name__ == '__main__':
pid = os.getpid()
print(f'=== pid = {pid}, this is python main')
xyz_test.callTLS()
multiprocessing.set_start_method('fork')
child = multiprocessing.Process(target=func)
child.start()
child.join()
# xyz_test.h
#ifndef SHARED_OBJ_H_
#define SHARED_OBJ_H_
#define PID_LOG(STR) \
auto pid = getpid(); \
printf("=== pid is %d, %s\n", pid, STR);
#define PRINT_ADDR() \
printf("\t now addr is %p\n", this);
void callTLS();
class A {
public:
A();
~A();
void call();
private:
int a = 0;
};
#endif
# xyz_test.cc
#include "shared_obj.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <thread>
#include <iostream>
static thread_local A test;
void __attribute__((constructor)) init() {
PID_LOG("so is loaded.");
}
void __attribute__((destructor)) fini() {
PID_LOG("so is unloaded.");
}
A::A() {
PID_LOG("this is A::A().");
PRINT_ADDR();
}
A::~A() {
PID_LOG("this is A::~A().");
PRINT_ADDR();
}
void A::call() {
PID_LOG("this is A::call().")
PRINT_ADDR();
}
void callTLS() {
test.call();
}
CPython versions tested on:
3.11
Operating systems tested on:
Linux
Linked PRs
- gh-127246
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
從 main_os_fork.py 和 main_mp_fork.py 開始,接著檢查 xyz_test.cc 擴充功能,並在 Linux 上使用 Python 3.11 比較它們的卸載輸出。檢查已連結的 PR gh-127246,並判斷不同的 .so teardown 行為是否符合預期,還是需要加入回歸測試並修正。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- cpp, linux, python
- 領域
- operating-systems
- Issue 類型
- 缺陷
- 難度
- 4/5
- 預估耗時
- 3-5 天
- 活躍度
- 停滯
- 描述清晰度
- 需要釐清
- 新手友好度
- 25/100