You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程环境下嵌入式Python与C++变量安全共享方案咨询

问题

我正在将Python集成到C应用中,通过Python脚本读取I2C传感器数据,目标是让Python与C代码并行运行,实现Python变量的持续更新与C++的访问。

我已在C中创建线程运行Python脚本,该脚本通过无限循环每秒获取传感器数据并更新变量,但需要将更新后的变量从Python传递到C供应用其他部分使用。我尝试通过在C++中定义全局atomic变量并从Python脚本更新它,但不确定这是否是最高效或正确的方案。

设备环境:Raspberry Pi 5,Python 3.10

相关代码:

#include <Python.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>

// Global variable to store the velocity as an atomic float to ensure thread-safe updates.
std::atomic<float> globalVelocity(0.0);

void UpdateVelocity() {
    Py_Initialize();
    PyObject* sysPath = PySys_GetObject("path");
    PyList_Append(sysPath, PyUnicode_FromString("/path/to/your/module"));

    PyObject *pName = PyUnicode_DecodeFSDefault("velocity_module");
    PyObject *pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        PyObject *pFunc = PyObject_GetAttrString(pModule, "get_velocity");
        if (pFunc && PyCallable_Check(pFunc)) {
            while (true) {
                PyObject *pValue = PyObject_CallObject(pFunc, NULL);
                if (pValue != NULL) {
                    double velocity = PyFloat_AsDouble(pValue);
                    globalVelocity.store(static_cast<float>(velocity)); 
                    std::cout << "Updated Velocity: " << velocity << " m/s" << std::endl;
                    Py_DECREF(pValue);
                } else {
                    PyErr_Print();
                    std::cerr << "Function call failed" << std::endl;
                }
                std::this_thread::sleep_for(std::chrono::seconds(1));  
            }
        } else {
            PyErr_Print();
            std::cerr << "Cannot find function 'get_velocity'" << std::endl;
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    } else {
        PyErr_Print();
        std::cerr << "Failed to load 'velocity_module'" << std::endl;
    }
    Py_Finalize();

}

int main() {
    std::thread velocityThread(UpdateVelocity);
    velocityThread.detach();

    while (true) {
        std::cout << "Main thread reading global velocity: " << globalVelocity.load() << " m/s" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));  
    }

    return 0;
}
解决方案

1. 你的atomic全局变量方案是可行且高效的

对于单个浮点型变量来说,std::atomic<float>是线程安全且性能最优的选择:

  • 原子操作是硬件级别的同步,不需要内核态的锁开销,在Raspberry Pi 5的ARM架构上支持良好
  • 你的代码实现逻辑正确:Python线程调用get_velocity获取值后,通过store原子写入,主线程用load原子读取,完全避免了数据竞争

小优化点:

  • 在单生产者单消费者的场景下,可以指定宽松内存序,比如globalVelocity.store(val, std::memory_order_relaxed)和globalVelocity.load(std::memory_order_relaxed),进一步降低性能开销
  • 避免全局变量:将atomic变量封装到类中,通过指针或引用传递给线程,代码结构更清晰

2. 多变量场景:互斥锁+结构体

如果后续需要共享多个传感器数据(如加速度、角度等),单个atomic无法保证多变量的原子性更新,此时可以用std::mutex配合结构体:

#include <mutex>

struct SensorData {
    float velocity;
    float acceleration;
};

std::mutex sensorMutex;
SensorData globalSensorData;

// Python线程更新逻辑
std::lock_guard<std::mutex> lock(sensorMutex);
globalSensorData.velocity = newVelocity;
globalSensorData.acceleration = newAcceleration;

// C++主线程读取逻辑
std::lock_guard<std::mutex> lock(sensorMutex);
float currentVel = globalSensorData.velocity;
float currentAcc = globalSensorData.acceleration;

这种方式确保多个变量的更新是原子性的,不会出现部分变量更新、部分未更新的中间状态。

3. 直接通过Python C API暴露C++对象

如果希望Python脚本直接操作C变量(而非C主动调用Python函数取值),可以把C++变量封装成Python扩展对象:

  • 用PyModule_AddObject将C++的atomic变量或结构体注册到Python模块中
  • Python脚本可直接修改该对象,底层自动触发线程安全的更新
    这种方式适合Python逻辑复杂、需要主动修改共享数据的场景,代码耦合度更低。

4. 异步队列通信

如果不需要实时同步,允许一定延迟,可以用std::queue配合条件变量实现生产者-消费者模型:

#include <queue>
#include <condition_variable>

std::queue<float> velocityQueue;
std::mutex queueMutex;
std::condition_variable cv;

// Python线程(生产者)逻辑
std::lock_guard<std::mutex> lock(queueMutex);
velocityQueue.push(newVelocity);
cv.notify_one();

// C++主线程(消费者)逻辑
std::unique_lock<std::mutex> lock(queueMutex);
cv.wait(lock, []{ return !velocityQueue.empty(); });
float latestVel = velocityQueue.back();
// 清空旧数据,只保留最新值
while (velocityQueue.size() > 1) {
    velocityQueue.pop();
}

这种方式适合传感器数据产生频率高于C++消费频率的场景,避免数据堆积。

总结

  • 单变量场景:优先使用你的std::atomic<float>方案,调整内存序可进一步优化性能
  • 多变量场景:用std::mutex+结构体保证原子性更新
  • 需要Python主动修改数据:通过Python C API暴露C++对象
  • 异步消费场景:用队列+条件变量实现解耦

内容的提问来源于stack exchange,提问作者user25086481

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:23:25