从多线程程序安全地删除一个对象(Delete an object securely from a m

2019-07-31 15:13发布

声明:既不升压,也不C ++ 11允许的。

我有一个程序,我在其中创建的实例Foo ,我与它在多个线程运行。 然后我想删除它安全地使这些线程不属于分段错误。

我添加了一个互斥体成员Foo每个线程函数运行时间将其锁定。 为了不同的线程不会互相冲突。

class Foo
{
    public:
        pthread_mutex_t mutex;
};

void* thread ( void* fooPtr )
{
    Foo* fooPointer = (Foo*) fooPtr;

    while ( 1 )
    {
        if ( fooPointer )
        {
            pthread_mutex_lock ( &fooPointer->mutex );
            /* some code, involving fooPointer */
            pthread_mutex_unlock ( &fooPointer->mutex );
        }
        else
        {
            pthread_exit ( NULL );
        }
    }
}

现在我想删除foo所以发生在线程没有错误安全。 我添加了一个析构函数Foo

Foo::~Foo()
{
    pthread_mutex_lock ( &mutex );
}

现在对象将不会被删除,直到所有线程完成电流回路。

现在的问题是:将互斥的实例被删除后可以解锁? 一个实例被删除后,所有的线程将结束? 我敢打赌,答案是no 。 所以我改变了析构函数,但现在看来,线程安全的:

Foo::~Foo()
{
    pthread_mutex_lock ( &mutex );
    pthread_mutex_unlock ( &mutex );
}

线程函数可以锁定互斥锁,并开始工作后的实例pthread_mutex_unlock ( &mutex ); 和对象之前被删除?

Answer 1:

现在缺少的是在这里完成时线程处理该规定的条件。 特定对象实例的删除是不是一个很好的条件。 您还没有该对象被删除告诉我们。 如果我们能看到这个代码,多余的背景下将是有益的。

我的建议是,而不是删除对象,设置(例如布尔活跃())在对象上的标志。 此标志将然后由所有线程进行检查,并在表示停止处理,那么线程将停止。 设置此标志,你正在删除Foo对象。 然后,一旦所有线程都停止,删除Foo对象。

如果删除的对象,并希望能够收购其互斥锁,你可能会得到一个崩溃,或者至少不稳定的行为,因为互斥是美孚的成员,它将与对象被销毁。

下面是我的意思的例子:

class Foo
{
    public:
        void lockMutex();
        void unlockMutex();
        // Active should be mutex protected as well
        // Or you could consider using a pthread_rwlock
        bool active() {return active_;}
        void setActive(bool a) {active_ = a;}
    private:
        pthread_mutex_t mutex;
        bool active_;
};

void* thread ( void* fooPtr )
{
    Foo* fooPointer = (Foo*) fooPtr;

    while ( 1 )
    {
        if ( fooPointer->active() )
        {
            fooPointer->lockMutex();
            /* some code, involving fooPointer */
            fooPointer->unlockMutex();
        }
        else
        {
            pthread_exit ( NULL );
        }
    }

    // somewhere else in the code
    fooPointer->setActive(false);
}

富:: SETACTIVE(真)必须被调用无论是在构造函数中,或创建对象时。 而且一旦线程停止Foo对象应该被删除,在pt​​hread_join后,最有可能的()已完成。



Answer 2:

让我们先从开始你的问题:

我有一个程序,我在其中创建富的一个实例,我用它在多个线程运行。 然后我想删除它安全地使这些线程不属于分段错误。

您不能删除的对象,它是在使用中。 互斥再多就会解决这个问题。

我添加了一个析构函数的Foo

当这是只运行Foo被删除。 其内容也没有多大关系,但:这是错误的,而其他线程还在使用美孚调用析构函数。

我想,当一个实例被删除线程安全地退出。 这怎么可能?

嗯,这是正确的问题。 我可以写一大堆供您使用代码,但这些代码将只是一个副本boost::weak_ptr 。 所以,我不会理会。 就拿升压代码自己。

升压不允许的。

那么,为什么你要问在计算器上? 这是本质相同的许可证。



Answer 3:

你的代码贴是不正确的,因为被破坏的步骤C ++对象吹:

obj->Foo::~Foo();

free memory //maybe delete if allocated by new

所以你的源仅protoecting析构函数而不是记忆中解脱出来。

也许源代码如下可以帮助你,这是简单粗暴,但我认为它可以工作

    class Foo 
    {

       public:
         void dosomething() {}
    };

    template<typename T>
    class Protect
    {   
    public: 
        struct auto_lock {
            auto_lock(pthread_mutex_t& mutex)
                : _mutex(mutex)
            {
                pthread_mutex_lock ( &_mutex );
            }
            ~ auto_lock() 
            {
                pthread_mutex_unlock ( &_mutex );
            }
            pthread_mutex_t& _mutex;
        };

        Protect(T*& p): _p(p) {}
        T* get() { return _p; }

        void lock() { pthread_mutex_lock ( &_mutex ); }
        void unlock() { pthread_mutex_unlock ( &_mutex );}
        pthread_mutex_t& getlock() { return _mutex; }

        void safe_release() { 
            auto_lock l(_mutex);
            if (_p != NULL)  {
                delete _p;
                _p = NULL;
            }
        }
    private:
        T*& _p;
        pthread_mutex_t _mutex;
    };

void* thread ( void* proPtr )
{
    Protect<Foo>* proPointer = (Protect<Foo>*) proPtr;

    while ( 1 )
    {
        Protect<Foo>::auto_lock l(proPointer->getlock());
        Foo* fooPtr = proPointer->get();
        if ( fooPtr )
        {
            fooPtr->dosomething();
        }
        else
        {
            pthread_exit ( NULL );
        }
    }
}


文章来源: Delete an object securely from a multi-threaded program