【问题标题】:Using a c++ std::mutex declared inside a python object使用在 python 对象中声明的 c++ std::mutex
【发布时间】:2018-05-02 10:39:44
【问题描述】:

小问题: 使用malloc获取对应内存后,如何在结构中初始化std::mutex?

更多细节: 我正在尝试使用后台线程制作一个 python 模块

我创建并运行线程没有任何问题,但如果我尝试使用存储在 Python 对象中的互斥锁,它会崩溃。

如果我在我的 cpp 文件的开头定义互斥锁,它就可以工作。但我更愿意将它存储在设备结构中

在我的 PyDevice.h 中

#include <Python.h>
#include "structmember.h"

typedef struct sSharedData
{
    bool mStop;
} sSharedData;

typedef struct sDevice
{
    PyObject_HEAD
    std::thread mDataThread;
    std::mutex mDataThreadMutex;
    sSharedData mDataThreadSharedData;
} sLeddarDevice;


PyObject *StartDataThread( sLeddarDevice *self, PyObject *args );
PyObject *StopDataThread( sLeddarDevice *self, PyObject *args );

static PyMethodDef Device_methods[] =
{
    { "StartDataThread", ( PyCFunction )StartDataThread, METH_NOARGS, "Start the thread." },
    { "StopDataThread", ( PyCFunction )StopDataThread, METH_NOARGS, "Stop the thread." },
    { NULL }  //Sentinel
};

static PyMemberDef Device_members[] =
{
    { NULL }  //Sentinel
};

static PyTypeObject LeddarDeviceType =
{
    PyObject_HEAD_INIT( NULL )
    0,                              //ob_size
    "LeddarPy.Device",              //tp_name
    sizeof( sDevice ),        //tp_basicsize
    0,                              //tp_itemsize
    ( destructor )Device_dealloc,   //tp_dealloc
    0,                              //tp_print
    0,                              //tp_getattr
    0,                              //tp_setattr
    0,                              //tp_compare
    0,                              //tp_repr
    0,                              //tp_as_number
    0,                              //tp_as_sequence
    0,                              //tp_as_mapping
    0,                              //tp_hash
    0,                              //tp_call
    0,                              //tp_str
    0,                              //tp_getattro
    0,                              //tp_setattro
    0,                              //tp_as_buffer
    Py_TPFLAGS_DEFAULT,             //tp_flags
    "Device object.",               // tp_doc
    0,                              //tp_traverse
    0,                              //tp_clear
    0,                              //tp_richcompare
    0,                              //tp_weaklistoffset
    0,                              //tp_iter
    0,                              //tp_iternext
    Device_methods,                 //tp_methods
    Device_members,                 //tp_members
    0,                              //tp_getset
    0,                              //tp_base
    0,                              //tp_dict
    0,                              //tp_descr_get
    0,                              //tp_descr_set
    0,                              //tp_dictoffset
    0,                              //tp_init
    0,                              //tp_alloc
    Device_new,                     //tp_new
};

在我的 PyDevice.cpp 中

#include "LeddarPyDevice.h"
//Constructor
PyObject *Device_new( PyTypeObject *type, PyObject *args, PyObject *kwds )
{
    sLeddarDevice *self;

    self = ( sLeddarDevice * )type->tp_alloc( type, 0 );

    if( self != nullptr )
    {
        self->mDataThreadSharedData.mStop = false;
    }

    return ( PyObject * )self;
}

//Destructor
void Device_dealloc( sLeddarDevice *self )
{
    DebugTrace( "Destructing device." );
    Py_TYPE( self )->tp_free( ( PyObject * )self );
}

PyObject *StartDataThread( sLeddarDevice *self, PyObject *args )
{
    DebugTrace( "Starting thread" );
    self->mDataThreadMutex.lock();
    self->mDataThreadSharedData.mStop = false;
    self->mDataThreadMutex.unlock();
    self->mDataThread = std::thread( DataThread, self );

    Py_RETURN_TRUE;
}

每当我尝试使用 self-&gt;mDataThreadMutex.lock() 时它都会崩溃。

我不确定互斥锁是否已正确初始化,我更习惯于在需要手动初始化的地方使用 pthread 互斥锁。

【问题讨论】:

标签: python c++ multithreading c++11


【解决方案1】:

Python 是用 C 编写的,因此它不会为您运行 C++ 构造函数/析构函数。没有它们std::mutex 只是一个毫无意义的结构,使用时会崩溃。你需要的是placement new某处(分配self之后?):

self = ( sLeddarDevice * )type->tp_alloc( type, 0 );
new (self) sLeddarDevice {};

第二行在self上调用sLeddarDevice的构造函数没有分配内存。该构造函数也会调用每个成员的构造函数。

您还必须在完成后手动调用析构函数:self-&gt;~sLeddarDevice();

在将 C++ 与 Python 结合使用时,您应该始终这样做。否则,在最好的情况下,您将泄漏内存。在更糟糕的情况下,遇到随机崩溃的未定义行为。

【讨论】:

  • 删除python对象时调用Device_dealloc,我可以从那里调用析构函数吗?
  • @DavidLevy 是的,你可以而且应该。请注意,我不确定 Python 的 tp_alloctp_free 将如何与 C++ 的构造函数和析构函数一起使用。有时将 C++ 与 C 代码结合起来很棘手。
  • 使用构造函数工作(没有初始化列表),使用描述符导致崩溃。一个小细节,new(self)是什么意思?这是我第一次看到 new 以这种方式使用
  • @DavidLevy 被称为“安置新”。它只运行构造函数而不分配内存(您将指针传递到它应该调用构造函数的位置)。查看链接和/或谷歌它。对于析构函数:before tp_free?
  • 哦,注意如果你不.join()线程或者分离它,析构函数将会崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 2013-12-29
相关资源
最近更新 更多