Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> delete std::thread без запуска потока 
V
    Опции темы
borisbn
Дата 22.2.2012, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Здравствуйте.
Столкнулся с такой проблемой: если создать std::thread, а затем "быстро" его удалить, то запуск всё равно происходит, но уже с удалённым объектом.
Вот код
Код

class Thread {
public:
    Thread() : th( 0 ) {}
    virtual ~Thread()
    {
        std::cout << this << " ~Thread()" << std::endl;
        if ( th )
            th->join();
        delete th;
    }
    void start() {
        th = new std::thread( std::bind( &Thread::run, this ) );
    }
protected:
    virtual void run() = 0;
    std::thread * th;
};

class ThreadImpl : public Thread {
protected:
    void run() {
        std::cout << this << " ThreadImpl::run " << std::endl;
    }
};

int main(int argc, char *argv[])
{
    std::vector< Thread* > v = { new ThreadImpl(), new ThreadImpl() };
    std::for_each( v.begin(), v.end(), []( Thread * t ) {
        std::cout << t << " starting" <<  std::endl;
        t->start();
    } );
    std::cout << "The end" << std::endl;
    std::for_each( v.begin(), v.end(), []( Thread * t ) {
        std::cout << t << " deleting" << std::endl;
        delete t;
    } );
}

http://liveworkspace.org/code/5bd9310f0a7f...fa0b73b5323d53e
вот вывод
Цитата

0x90fae00 starting
0x90fae10 starting
The end
0x90fae00 deleting
0x90fae00 ~Thread()
0x90fae10 ThreadImpl::run 
pure virtual method called
terminate called without an active exception


видно, что 1-й поток отработал как надо, а 0-й удалился раньше, чем отработал и bind'нутая ф-ция run() теперь указывает в никуда.
Вопрос: что я не так делаю ? Как убедиться, что запуск потока прошёл - желательно в ф-ции start(), но можно и в деструкторе.
Спасибо


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
azesmcar
Дата 22.2.2012, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Ты делаешь join в деструкторе базового класса Thread, который вызывается уже после уничтожения его наследника (т.е. ThreadImpl). Т.е. здесь join() в принципе может и не успеть сработать, удаляется ThreadImpl, потом поток запускает функцию run(), но объекта ThreadImpl уже не существует

Можно просто перенести деструктор в ThreadImpl, но вообще я бы не стал писать join() в деструкторе.

Это сообщение отредактировал(а) azesmcar - 22.2.2012, 11:37
PM   Вверх
borisbn
Дата 22.2.2012, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(azesmcar @  22.2.2012,  11:34 Найти цитируемый пост)
Можно просто перенести деструктор в ThreadImpl, 

Спасибо. Перенёс - заработало. Теперь, кажется, понял в чём дело - join() не то, чтобы не отрабатывал, а до него просто не доходило управление. В деструкторе наследника грохаласьего  виртуальная таблица, затем управление переключалось на поток, который пытался запустить run()... Спасибо.
Вот, если кому нужно, доработанный вариант (правда, в наследнике приходится вызывать wait())
Код

class Thread {
public:
    Thread() : th( 0 ) {}
    virtual ~Thread() {
        delete th;
    }
    void start() {
        th = new std::thread( &Thread::run, this );
    }
    void wait() {
        if ( th ) {
            th->join();
        }
    }
protected:
    Thread( const Thread & );
    Thread & operator=( const Thread & );
    virtual void run() = 0;
    std::thread * th;
};

class ThreadImpl : public Thread {
public:
    ~ThreadImpl() {
        wait();
    }
protected:
    void run() {
        std::cout << this << " ThreadImpl::run()" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    std::vector< std::shared_ptr< Thread > > v =
        {
            std::shared_ptr< Thread >( new ThreadImpl() ),
            std::shared_ptr< Thread >( new ThreadImpl() )
        };
    std::for_each( v.begin(), v.end(), std::bind( &Thread::start, _1 ) );
    std::cout << "The end" << std::endl;
}

http://liveworkspace.org/code/8554941a87fb...1a557fbbf9c6076

Тему закрываю, но если у кого есть предложения по импрувменту класса - велкам.

azesmcar, сорри, что теперь репутация не круглая smile

Это сообщение отредактировал(а) borisbn - 22.2.2012, 13:01


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
azesmcar
Дата 22.2.2012, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(borisbn @  22.2.2012,  12:57 Найти цитируемый пост)
Тему закрываю, но если у кого есть предложения по импрувменту класса - велкам.

Ну давай что ли, раз такое дело smile 
Зачем нужен этот класс и какую задачу он пытается решить?

Добавлено через 34 секунды
Цитата(borisbn @  22.2.2012,  12:57 Найти цитируемый пост)
Тему закрываю, но если у кого есть предложения по импрувменту класса - велкам.

Ну давай что ли, раз такое дело smile 
Зачем нужен этот класс и какую задачу он пытается решить?

PM   Вверх
borisbn
Дата 22.2.2012, 14:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Насмотрелся на Qt...  smile 
Хотел обернуть std::thread, чтобы запуск потока происходил не в конструкторе, а в каком-нибудь start(), а также чтобы при разрушении этого класса деструктор дожидался бы окончания работы потока. В общем, чтобы использование такого класса сводилось бы к минимуму: наследоваться и переписать ф-цию run()
Код

class ThreadImpl : public Thread {
void run() {
    ...
}
};

int main() {
     ThreadImpl th;
     th.start();
}

пока не получается...

Это сообщение отредактировал(а) borisbn - 22.2.2012, 14:06


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 22.2.2012, 14:41 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(borisbn @  22.2.2012,  13:06 Найти цитируемый пост)
 В общем, чтобы использование такого класса сводилось бы к минимуму: наследоваться и переписать ф-цию run()

брр...  smile

P.S. надеюсь меня правильно поймут... 


Это сообщение отредактировал(а) mes - 22.2.2012, 14:44


--------------------
PM MAIL WWW   Вверх
azesmcar
Дата 22.2.2012, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(borisbn @  22.2.2012,  14:06 Найти цитируемый пост)
Хотел обернуть std::thread, чтобы запуск потока происходил не в конструкторе, а в каком-нибудь start(), а также чтобы при разрушении этого класса деструктор дожидался бы окончания работы потока. В общем, чтобы использование такого класса сводилось бы к минимуму: наследоваться и переписать ф-цию run()

Для чего? Чтобы создать поток? Есть std::future, std::async, пользователю нужно только написать функцию, зачем наследовать класс? Зачем нужен такой класс вообще? Этот объект будет постоянно висеть в памяти и выполнять какую нибудь задачу или ты его создашь, поток завершиться и объект можно удалять?
Если первое, то это не очень-то хорошо. Поток скорее всего не будет работать круглосуточно, он будет иногда выполнять некую работу, а в остальное время будет спать (читай зря потреблять ресурсы).
Если второе, то зачем для этого писать целый класс?
PM   Вверх
borisbn
Дата 22.2.2012, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(azesmcar @  22.2.2012,  14:52 Найти цитируемый пост)
Этот объект будет постоянно висеть в памяти и выполнять какую нибудь задачу

да
Цитата(azesmcar @  22.2.2012,  14:52 Найти цитируемый пост)
 Поток скорее всего не будет работать круглосуточно, он будет иногда выполнять некую работу, а в остальное время будет спать (читай зря потреблять ресурсы)

Какие ресурсы он будет потреблять ? Память ? Ну.. этим я могу пожертвовать. Дело в том, что я стараюсь делать потоки таким образом, чтобы они ожидали какого-нибудь события (в венде WaitForSingleObject) и по наступлении - делали своё чёрное дело - и опять ожидали.

Цитата(mes @  22.2.2012,  14:41 Найти цитируемый пост)
брр...

Хммм. Несколько раз слышал такое мнение о наследовании, но никто не мог толком объяснить, чем это хуже, чем передавать в класс "поток" свой функтор ? Надеюсь Вы сможете втолковать.

Добавлено через 1 минуту и 44 секунды
Дико извиняюсь за офф-топ, но не создавать же ради этого тему  smile 
А что, на LWS не работают делегирующие конструкторы ???
http://liveworkspace.org/code/c8c5d425f349...87a581cbfe19f24



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
azesmcar
Дата 22.2.2012, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата(borisbn @  22.2.2012,  15:12 Найти цитируемый пост)
Хммм. Несколько раз слышал такое мнение о наследовании, но никто не мог толком объяснить, чем это хуже, чем передавать в класс "поток" свой функтор ? Надеюсь Вы сможете втолковать.

А чем собственно класс лучше? Как минимум это больше кода и вызов виртуальной функции там, где он абсолютно не нужен. Еще это ненужные классы и наследование. В чем плюс такого класса?

Цитата(borisbn @  22.2.2012,  15:12 Найти цитируемый пост)
Какие ресурсы он будет потреблять ? Память ? Ну.. этим я могу пожертвовать. 

Вообще-то если вдуматься можно и объекты по константной ссылке не передавать smile 

Цитата(borisbn @  22.2.2012,  15:12 Найти цитируемый пост)
делали своё чёрное дело - и опять ожидали

А не лучше ли ему заняться делом?
PM   Вверх
boostcoder
Дата 22.2.2012, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



borisbn, std::thread/boost::thread прекрасны тем, что могут выполнить в потоке любой callable объект, без явного создания/оборачивания его в какую-либо сущность. а ты их так использовать решил.. бррр....

Цитата(borisbn @  22.2.2012,  15:12 Найти цитируемый пост)
на LWS не работают делегирующие конструкторы ?

в 4.6.2 они не реализованы.

PM WWW   Вверх
borisbn
Дата 22.2.2012, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(azesmcar @  22.2.2012,  17:24 Найти цитируемый пост)
А чем собственно класс лучше?

Ну, как минимум тем, что он сам следит за тем, чтобы дождаться завершения работы потока. Т.е., чтобы не было такой ситуации
Код

void foo( Object * obj ) {
   obj->чего-то-там();
}
int main() {
    Object obj;
    std::thread t( foo, &obj );
    // а вот тут я забыл вызвать t.join();
}


Цитата(azesmcar @  22.2.2012,  17:24 Найти цитируемый пост)
 Как минимум это больше кода и вызов виртуальной функции там, где он абсолютно не нужен

Кол-во кода - сравнимо, а вызов виртуальной функции происходит один раз при запуске потока.

Цитата(azesmcar @  22.2.2012,  17:24 Найти цитируемый пост)
А не лучше ли ему заняться делом? 

ну... вот пример такого потока
Код

void PlateThread::run() {
    while ( m_plate->hasData() ) { // hasData() ожидает прихода данных - "висит" в WaitFor-функции
        Data d = m_plate->readData();
        m_dataProcessor->go( d );
    }
}

Цитата(boostcoder @  22.2.2012,  17:26 Найти цитируемый пост)
а ты их так использовать решил.. бррр....

второе бррр... за сегодня и ни одного объяснения чем подход с callable-объектом лучше


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 22.2.2012, 17:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  22.2.2012,  17:49 Найти цитируемый пост)
// а вот тут я забыл вызвать t.join();

RAII.

Цитата(borisbn @  22.2.2012,  17:49 Найти цитируемый пост)
ни одного объяснения чем подход с callable-объектом лучше

объяснил.

PM WWW   Вверх
borisbn
Дата 23.2.2012, 08:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



> RAII.
А я что пытаюсь сделать?

Добавлено через 5 минут и 1 секунду
Кста, с праздником, господа!


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mes
Дата 23.2.2012, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(borisbn @  23.2.2012,  07:49 Найти цитируемый пост)
А я что пытаюсь сделать?

привинтить наследование туда, где можно сделать обертку адаптер..
 smile 


--------------------
PM MAIL WWW   Вверх
azesmcar
Дата 23.2.2012, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



borisbn

Я не совсем понимаю чем твой вариант лучше например вот такого?
Код

#include <iostream>
#include <string>
#include <thread>

class thread_guard
{
public:
    explicit thread_guard(std::thread& t): th(t) {}
    ~thread_guard()
    {
        if(th.joinable())
        {
            th.join();
        }
    }
/*
    thread_guard(const thread_guard&) = delete;
    thread_guard& operator = (const thread_guard&) = delete;
*/
private:
    std::thread& th;
};

void thread_proc(const std::string& str)
{
    std::cout << "thread1: " << str << std::endl;
};

int main()
{
    std::thread thread(thread_proc, "hello");
    thread_guard guard(thread);
}



Это сообщение отредактировал(а) azesmcar - 23.2.2012, 09:47
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0681 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.