0

免责声明:Boost 和 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 );对象被删除之后和之前锁定互斥锁并开始操作实例吗?

4

3 回答 3

11

让我们从你的问题开始:

我有一个程序,我在其中创建了一个 Foo 实例,并在多个线程中对其进行操作。然后我想安全地删除它,这样那些线程就不会陷入分段错误。

您不能删除正在使用的对象。没有多少互斥锁可以解决这个问题。

我已经向 Foo 添加了一个析构函数

这仅在Foo被删除时运行。不过,它的内容并不重要:在其他线程仍在使用 Foo 时调用 dtor 是错误的。

我希望在删除实例时线程安全退出。这怎么可能?

嗯,这是正确的问题。我可以编写很多代码供您使用,但这些代码只是boost::weak_ptr. 所以,我不会打扰。只需自己获取升压代码。

不允许升压。

那你为什么要在 StackOverflow 上问呢?这基本上是相同的许可证。

于 2012-09-17T08:52:14.140 回答
1

这里缺少的是指示线程处理何时完成的条件。删除特定对象实例不是一个好的条件。您还没有向我们展示删除对象的位置。如果我们可以在代码中看到这一点,那么额外的上下文将会很有帮助。

我建议不要删除对象,而是在对象上设置一个标志(例如 bool active())。然后所有线程都会检查这个标志,当它指示停止处理时,线程将停止。在当前删除 Foo 对象的位置设置此标志。然后一旦所有线程都停止,删除 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);
}

Foo::setActive(true) 必须在构造函数中调用,或者在创建对象时调用。一旦线程停止,最有可能在 pthread_join() 完成之后,应该删除 Foo 对象。

于 2012-09-17T08:50:07.827 回答
-1

您发布的代码不正确,因为 c++ 对象被步骤破坏:

obj->Foo::~Foo();

free memory //maybe delete if allocated by new

所以你的来源只是保护析构函数而不是释放内存本身。

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

    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 );
        }
    }
}
于 2012-09-17T09:20:02.570 回答