Расовое состояние с собой - PullRequest
1 голос
/ 25 апреля 2011

У меня есть класс с функциями-членами, которые требуют, чтобы boost :: unique_lock был получен на соответствующем мьютексе перед выполнением их операции.Однако, когда функция-член вызывается при существующем boost :: unique_lock, она сама блокируется.

#include <iostream>
#include "boost/thread.hpp"
#include "boost/foreach.hpp"
#include <list>
class example {
    private:
    std::list< int > int_array;
    std::list< int >::iterator array_iterator;
    mutable boost::shared_mutex array_mutex;
    public:
    /*
     * Move the iterator forward.
     */
    inline example & next( ) {
        boost::unique_lock< boost::shared_mutex > lock( array_mutex );

        array_iterator++;
        if( array_iterator == int_array.end( ) ) {
            array_iterator = int_array.begin( );
        }

        return *this;
    }

    /*
     * Get int_array_mutex.
     */
    inline boost::shared_mutex & mutex( ) const {
        return array_mutex;
    }

    /*
     * Get int_array.
     */
    inline std::list< int > & array() {
        return int_array;
    }
};

int main() {
    example example_instance;

    boost::unique_lock< boost::shared_mutex> lock(example_instance.mutex());

    //Manipulate int_array...
    example_instance.array().push_back(1);
    example_instance.array().push_back(2);
    example_instance.array().push_back(3);
    example_instance.array().push_back(4);
    BOOST_FOREACH(int & x, example_instance.array()) {
        x++;
    }

    //Causes deadlock
    example_instance.next();

    std::cout << "This shall not be emitted." << std::endl;

    return 0;
}

Как это исправить?

Ответы [ 2 ]

3 голосов
/ 25 апреля 2011

Я не использовал усиление потоков, но если я правильно прочитал ваш код, вы заблокировали мьютекс в своей основной функции, а затем вызвали метод examlpe_instance next(), который также пытается получить блокировку мьютекса массива. ... естественно, это может привести к тупику, поскольку не похоже, что блокировка повторная.

Почему вы получаете блокировку в основной функции?

Обновление:

Вы не можете повторно получить блокировку дважды в пределах одной и той же области, если только у вас нет повторной блокировки (которой у вас нет), поэтому попробуйте изменить область:

int main() {
    example example_instance;

    {// new scope
        boost::unique_lock< boost::shared_mutex> lock(example_instance.mutex());

        //Manipulate int_array...
        example_instance.array().push_back(1);
        example_instance.array().push_back(2);
        example_instance.array().push_back(3);
        example_instance.array().push_back(4);
        BOOST_FOREACH(int & x, example_instance.array()) {
            x++;
        }
    }// end scope

    // should not cause deadlock now
    example_instance.next();

    std::cout << "This shall not be emitted." << std::endl;

    return 0;
}

Если boost работает так, как я себе представляю, то boost должен снять блокировку, как только она выйдет из области видимости. Попробуйте приведенную выше модификацию и посмотрите, есть ли у вас тупик (если он все-таки есть, вам нужно как-то явно снять блокировку, но я не знаю, как это делается в boost).

0 голосов
/ 25 апреля 2011

То, что вы хотите - это recurisive_mutex, который более известен как мьютекс с повторным входом. Это позволит вам блокировать один и тот же мьютекс несколько раз в одном потоке, не вызывая взаимоблокировок. Итак, чтобы исправить ваш пример, просто замените все экземпляры shared_mutex на recursive_mutex, и это будет работать.

Проблема в том, что вы больше не можете использовать shared_lock и upgrade_to_unique_lock, так как они оба требуют, чтобы у вас был shared_mutex. Оказывается, согласно этим двум ссылкам похоже, что shared_mutex в любом случае плохая идея. Если вам действительно нужен shared_mutex, вам придется написать свой shared_recursive_mutex, потому что Boost его не предоставляет.

...