Повысить возможную утечку памяти - PullRequest
0 голосов
/ 15 января 2012

Поскольку я начал создавать небольшой проект, целью которого является поддержка кроссплатформенности, я выбрал boost 1.47 для взаимодействия с базовой ОС. Мой проект нуждался в многопоточности, поэтому я выполнил небольшую обертку над буст-потоками, чтобы удовлетворить свои потребности.

Мало я знал, что boost, очевидно, оставляет поток в памяти после разрушения его объекта (?), Или же он может иметь какую-то возможность утечки памяти.

Реализация моей обертки имеет scoped_ptr типа thread, и ptr с областью видимости инициализируется, когда кто-либо вызывает функцию start () в классе обертки. Работающий поток будет остановлен из основного потока с помощью thread-> interrupt (), а деструктор будет вызван из функции-оболочки. (Деструктор структуры процедуры потока, в которой есть оператор () ().

Вот реализация класса оболочки: (примечание: i_exception и пара других функций являются частью других компонентов проекта)

#define TIMED_JOIN boost::posix_time::milliseconds(1)

namespace utils
{
    struct thread_threadable
    {
        template<typename T> friend class ut_thread;
    private:
        boost::shared_ptr<thread_threadable> instance;
    public:
        virtual ~thread_threadable() {}
        virtual void operator()() = 0;
    };

    template<typename T = thread_threadable>
    class ut_thread
    {
    public:
        typedef T proc_t;
    private:
        boost::scoped_ptr<boost::thread> thr;
        boost::shared_ptr<proc_t> proc;
    public:
        explicit ut_thread(const boost::shared_ptr<proc_t> &procedure) : proc(procedure) {}
        ~ut_thread();

        void start();
        void stop();

        bool running() const {return this->thr.get() != NULL;}
        proc_t &procedure() const
        {
            BOOST_ASSERT(this->proc.get() != NULL);
            return *this->proc;
        }
    };
}
typedef utils::thread_threadable threadable;

template<typename T>
utils::ut_thread<T>::~ut_thread()
{
    if(this->thr.get() != NULL)
    {
        BOOST_ASSERT(this->proc.get() != NULL);
        this->stop();
    }
}
template<typename T>
void utils::ut_thread<T>::start()
{
    if(this->thr.get() != NULL)
        i_exception::throw_this("another thread of this procedure is already running");
    if(this->proc.get() == NULL)
        i_exception::throw_this("procedure object not initialized");

    this->proc->instance = this->proc;

    this->thr.reset(new boost::thread(boost::ref(*this->proc)));
    this->thr->timed_join(TIMED_JOIN);
}
template<typename T>
void utils::ut_thread<T>::stop()
{
    if(this->thr.get() == NULL)
        i_exception::throw_this("no thread was running");

    this->thr->interrupt();
    this->proc->~T();
    this->thr.reset(NULL);
}

И затем, проверив функциональность этого класса-оболочки, я сделал тест для main.cpp:

struct my_thr : public utils::thread_threadable
{
    void operator()()
    {
        while(true);
    }
};

int main()
{
    while(true)
    {
        utils::ut_thread<> thr(boost::shared_ptr<threadable>(new my_thr));
        utils::ut_thread<> thr1(boost::shared_ptr<threadable>(new my_thr));
        thr.start();
        thr1.start();
        boost::this_thread::sleep(boost::posix_time::seconds(1));
    }
    return 0;
}

В этот момент я заметил, что эти потоки не разрушаются, они будут оставаться в памяти, пока программа не завершится. Они также продолжают выполнять оператор while (true).

Итак, я спрашиваю, что может быть причиной такого поведения? Это что-то определено, или просто ошибка или что-то еще?

1 Ответ

3 голосов
/ 15 января 2012

Прежде всего interrupt остановит поток только на определенном ìnterruption points (взятом из boost::threads документации, немного переформатирован):

Предопределенные точки прерывания

Следующие функции являются точками прерывания, которые будут выбрасывать boost :: thread_interrupted если прерывание включено для текущего поток, и прерывание запрашивается для текущего потока:

boost::thread::join()
boost::thread::timed_join()
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::thread::sleep()
boost::this_thread::sleep()
boost::this_thread::interruption_point()

Поскольку в вашем потоке нет ни одного из них, вызов interrupt() не должен иметь никакого эффекта.

Теперь для уничтожения thread:

~ нить ();

Эффекты: Если * это связано с потоком выполнения, вызывает detach (). Уничтожает * это.

Броски: Ничего.

timed_join(), который вы вызвали в потоке, должен потерпеть неудачу, так как поток не завершит свое выполнение так быстро. Поэтому вы не join (или detach, но это не изменит конечного результата) ваших потоков, то есть они имеют связанный поток выполнения , когда они уничтожены. Поэтому они отстранены, что означает, что они будут работать до тех пор, пока не закончатся, даже если они больше не контролируются объектом boost::thread. Поскольку они выполняются и имеют бесконечный цикл, для завершения их выполнения может потребоваться некоторое время.

Как Sidenote: если вы решите сменить C ++ на 11 std::threads позже, вы должны заметить, что уничтожение без ручного вызова join() или detach() не является допустимым кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...