| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > delete std::thread без запуска потока |
| Автор: borisbn 22.2.2012, 11:20 | ||||
| Здравствуйте. Столкнулся с такой проблемой: если создать std::thread, а затем "быстро" его удалить, то запуск всё равно происходит, но уже с удалённым объектом. Вот код
http://liveworkspace.org/code/5bd9310f0a7ff44b6fa0b73b5323d53e вот вывод
видно, что 1-й поток отработал как надо, а 0-й удалился раньше, чем отработал и bind'нутая ф-ция run() теперь указывает в никуда. Вопрос: что я не так делаю ? Как убедиться, что запуск потока прошёл - желательно в ф-ции start(), но можно и в деструкторе. Спасибо |
| Автор: azesmcar 22.2.2012, 11:34 |
| Ты делаешь join в деструкторе базового класса Thread, который вызывается уже после уничтожения его наследника (т.е. ThreadImpl). Т.е. здесь join() в принципе может и не успеть сработать, удаляется ThreadImpl, потом поток запускает функцию run(), но объекта ThreadImpl уже не существует Можно просто перенести деструктор в ThreadImpl, но вообще я бы не стал писать join() в деструкторе. |
| Автор: borisbn 22.2.2012, 12:57 | ||
Спасибо. Перенёс - заработало. Теперь, кажется, понял в чём дело - join() не то, чтобы не отрабатывал, а до него просто не доходило управление. В деструкторе наследника грохаласьего виртуальная таблица, затем управление переключалось на поток, который пытался запустить run()... Спасибо. Вот, если кому нужно, доработанный вариант (правда, в наследнике приходится вызывать wait())
http://liveworkspace.org/code/8554941a87fb33a781a557fbbf9c6076 Тему закрываю, но если у кого есть предложения по импрувменту класса - велкам. azesmcar, сорри, что теперь репутация не круглая |
| Автор: borisbn 22.2.2012, 14:06 | ||
| Насмотрелся на Qt... Хотел обернуть std::thread, чтобы запуск потока происходил не в конструкторе, а в каком-нибудь start(), а также чтобы при разрушении этого класса деструктор дожидался бы окончания работы потока. В общем, чтобы использование такого класса сводилось бы к минимуму: наследоваться и переписать ф-цию run()
пока не получается... |
| Автор: mes 22.2.2012, 14:41 | ||
брр... P.S. надеюсь меня правильно поймут... |
| Автор: azesmcar 22.2.2012, 14:52 | ||
Для чего? Чтобы создать поток? Есть std::future, std::async, пользователю нужно только написать функцию, зачем наследовать класс? Зачем нужен такой класс вообще? Этот объект будет постоянно висеть в памяти и выполнять какую нибудь задачу или ты его создашь, поток завершиться и объект можно удалять? Если первое, то это не очень-то хорошо. Поток скорее всего не будет работать круглосуточно, он будет иногда выполнять некую работу, а в остальное время будет спать (читай зря потреблять ресурсы). Если второе, то зачем для этого писать целый класс? |
| Автор: borisbn 22.2.2012, 15:12 | ||||
да
Какие ресурсы он будет потреблять ? Память ? Ну.. этим я могу пожертвовать. Дело в том, что я стараюсь делать потоки таким образом, чтобы они ожидали какого-нибудь события (в венде WaitForSingleObject) и по наступлении - делали своё чёрное дело - и опять ожидали. Хммм. Несколько раз слышал такое мнение о наследовании, но никто не мог толком объяснить, чем это хуже, чем передавать в класс "поток" свой функтор ? Надеюсь Вы сможете втолковать. Добавлено через 1 минуту и 44 секунды Дико извиняюсь за офф-топ, но не создавать же ради этого тему А что, на LWS не работают делегирующие конструкторы ??? http://liveworkspace.org/code/c8c5d425f349ee33c87a581cbfe19f24 |
| Автор: azesmcar 22.2.2012, 17:24 | ||||
А чем собственно класс лучше? Как минимум это больше кода и вызов виртуальной функции там, где он абсолютно не нужен. Еще это ненужные классы и наследование. В чем плюс такого класса?
Вообще-то если вдуматься можно и объекты по константной ссылке не передавать А не лучше ли ему заняться делом? |
| Автор: boostcoder 22.2.2012, 17:26 |
| borisbn, std::thread/boost::thread прекрасны тем, что могут выполнить в потоке любой callable объект, без явного создания/оборачивания его в какую-либо сущность. а ты их так использовать решил.. бррр.... в 4.6.2 они не реализованы. |
| Автор: borisbn 22.2.2012, 17:49 | ||||||
Ну, как минимум тем, что он сам следит за тем, чтобы дождаться завершения работы потока. Т.е., чтобы не было такой ситуации
Кол-во кода - сравнимо, а вызов виртуальной функции происходит один раз при запуске потока. ну... вот пример такого потока
второе бррр... за сегодня и ни одного объяснения чем подход с callable-объектом лучше |
| Автор: boostcoder 22.2.2012, 17:54 |
RAII. объяснил. |
| Автор: borisbn 23.2.2012, 08:49 |
| > RAII. А я что пытаюсь сделать? Добавлено через 5 минут и 1 секунду Кста, с праздником, господа! |
| Автор: mes 23.2.2012, 09:45 |
привинтить наследование туда, где можно сделать обертку адаптер.. |
| Автор: azesmcar 23.2.2012, 09:45 | ||
| borisbn Я не совсем понимаю чем твой вариант лучше например вот такого?
|
| Автор: borisbn 23.2.2012, 11:45 | ||||
Меня не устраивает создание потока пользователем "снаружи". Плюс к тому, мне не нравится, что поток стартует при создании объекта. Тогда уж так
http://liveworkspace.org/code/f8c23130ce83878b0a25f5165c8506b1 Кстати, я уже спрашивал, и, помнится, получил отрицательный ответ, но может что-нибудь изменилось Как бы в конструкторе этого класса передать вариадик-параметры для m_func... Чтобы было как-то так
|
| Автор: mes 23.2.2012, 12:20 | ||
можно поток и внутрь чего то запихать.. Суть в том что "рабочая функция выполняемая в потоке" не является наследником потока..
а почему нелзя связать аргументы с функцией до конструктора ? |
| Автор: azesmcar 23.2.2012, 14:52 | ||
Почему? На то есть аргументы?
Поток стартует тогда, когда создается, что в этом плохого? bind кстати здесь не нужен. std::thread сам поддерживает эту функциональность. |
| Автор: borisbn 23.2.2012, 16:49 | ||||||
Можно, конечно, но в 99% случаев вызов конструктора будет выглядеть примерно так
я же хочу избавить пользователя от лишнего bind, чтобы вызов выглядел так
ну... мне хочется, чтобы пользователь просто сказал: "выполняй вот эту ф-цию в отдельном потоке и когда я разрушу твой класс - дождись окончания работы этой ф-ции", т.е. чтобы пользователь не заморачивался созданием ненужных ему классов типа std::thread Хочу как-то разделить создание объекта, отвечающего за поток и собственно запуск потока. Мой объект может быть членом какого-то класса (не указателем, а просто членом класса) и не хотелось бы, чтобы при создании такого объекта что-то "само" запускалось.
это я знаю, но мне тогда пришлось бы хранить и метод и указатель на объект... а в случае с методом с переменным кол-вом параметров - вообще хз как |
| Автор: mes 23.2.2012, 18:20 | ||||||
http://liveworkspace.org/code/1b8cacf4db3ad02c39e3d27f1c4ab4b3 Добавлено через 56 секунд
имелось ввиду объектов ? Добавлено через 6 минут и 24 секунды borisbn, приведите пример кодом, того чего хотите в результате.. Добавлено через 7 минут и 26 секунд
а понял... Добавлено через 8 минут и 53 секунды см пример азесмьцаря с прошлой страницы, только вместо передачи охранику потока , передавайте аргументы для бинда.. |
| Автор: borisbn 24.2.2012, 14:19 | ||||
гыыы. конечно. классы типа std::thread создают бустовцы и комитет)))
оО. То, что надо. Спасибо. В итоге вот, что получилось
http://liveworkspace.org/code/f2678918c5b3564c419b97ce2b342480 |
| Автор: boostcoder 24.2.2012, 14:55 |
| Все равно не понял, для чего эта обертка нужна, и разве она хоть что-то упрощает?.. к тому же, у обертки, потенциально ооочень(!) серьезная утечка ресурсов ;) |
| Автор: borisbn 25.2.2012, 14:20 | ||
несколько раз вызов start() ? согласен. допилю. |