Russian Qt Forum
Май 22, 2024, 11:11 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с потоками  (Прочитано 6717 раз)
like-nix
Гость
« : Апрель 09, 2011, 02:57 »

Подскажите как правильно работать с потоками.

Сейчас я работаю с потоками так в главном потоке создаю их через new в конце функции run потока вызываю deleteLater().

Но тогда valgrind в логах пишет
Код:
1,284 (20 direct, 1,264 indirect) bytes in 1 blocks are definitely lost in loss record

Если я использую умные указатели например так

Код:
m_FooThreadPtr = QSharedPointer<FooThread>(new FooThread);

Ситуация не меняется

Если я использую умные указатели так

Код:
m_FooThreadPtr = QSharedPointer<FooThread>(new FooThread, &QObject::deleteLater);

Ситуация немного меняется, меньше байт теряется
Вот полный текст сообщения в логах

Код:
==3164== 894 (20 direct, 874 indirect) bytes in 1 blocks are definitely lost in loss record 241 of 267
==3164==    at 0x4023F02: operator new(unsigned int) (vg_replace_malloc.c:214)
==3164==    by 0x8058A62: FooThread:: FooThread () (FooThread.cpp:27)
==3164==    by 0x8061EEE: FooDialog:: FooDialog (QWidget*) (FooDialog.cpp:11)
==3164==    by 0x804FD0D: MainWindow::slotRemove() (MainWindow.cpp:315)
==3164==    by 0x8063F5F: MainWindow::qt_metacall(QMetaObject::Call, int, void**) (moc_MainWindow.cpp:95)
==3164==    by 0x4D28142: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (qmetaobject.cpp:237)
==3164==    by 0x4D385A3: QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (qobject.cpp:3272)
==3164==    by 0x491F958: QAbstractButton::clicked(bool) (moc_qabstractbutton.cpp:206)
==3164==    by 0x45E6678: QAbstractButtonPrivate::emitClicked() (qabstractbutton.cpp:546)
==3164==    by 0x45E7E7F: QAbstractButtonPrivate::click() (qabstractbutton.cpp:539)
==3164==    by 0x45E80FB: QAbstractButton::mouseReleaseEvent(QMouseEvent*) (qabstractbutton.cpp:1121)
==3164==    by 0x41EE8B8: QWidget::event(QEvent*) (qwidget.cpp:8187)

но в логах программы появляются сообщения

Код:
QObject: shared QObject was deleted directly. The program is malformed and may crash.

Вообще в отчете valgrind очень много таких сообщений

Код:
==3164== 4,048 bytes in 22 blocks are possibly lost in loss record 262 of 267
==3164==    at 0x4022A92: memalign (vg_replace_malloc.c:532)
==3164==    by 0x4022AE2: posix_memalign (vg_replace_malloc.c:660)
==3164==    by 0x51605D3: ??? (in /usr/lib/libglib-2.0.so.0.1600.6)
==3164==    by 0x51617E0: g_slice_alloc (in /usr/lib/libglib-2.0.so.0.1600.6)
==3164==    by 0x5137BEC: ??? (in /usr/lib/libglib-2.0.so.0.1600.6)
==3164==    by 0x5175D94: g_get_language_names (in /usr/lib/libglib-2.0.so.0.1600.6)
==3164==    by 0x5104476: g_thread_init (in /usr/lib/libgthread-2.0.so.0.1600.6)
==3164==    by 0x4D52A09: QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(_GMainContext*) (qeventdispatcher_glib.cpp:299)
==3164==    by 0x424809C: QGuiEventDispatcherGlibPrivate::QGuiEventDispatcherGlibPrivate() (qguieventdispatcher_glib.cpp:171)
==3164==    by 0x4248182: QGuiEventDispatcherGlib::QGuiEventDispatcherGlib(QObject*) (qguieventdispatcher_glib.cpp:186)
==3164==    by 0x420E07F: QApplicationPrivate::createEventDispatcher() (qapplication_x11.cpp:605)
==3164==    by 0x4D25FF8: QCoreApplication::init() (qcoreapplication.cpp:552)

Т.е. мои утечки из 292 блоков только 2(те которые из моих исходников). Если я правильно читаю логи.
« Последнее редактирование: Апрель 09, 2011, 03:07 от like-nix » Записан
like-nix
Гость
« Ответ #1 : Апрель 09, 2011, 03:05 »

Не большое дополнение поток завершается нормально от него приходит сигнал finished
Записан
like-nix
Гость
« Ответ #2 : Апрель 09, 2011, 03:09 »

Параметры с которми запускал valgrind:
--leak-check=yes --leak-resolution=med
Записан
brankovic
Гость
« Ответ #3 : Апрель 09, 2011, 12:53 »

как правильно не знаю, но как-то делал такое и оно работало:

Код
C++ (Qt)
struct Thread : public QThread
{
  ...
 
  Thread (QObject *parent)
  {
     connect (this, SIGNAL (finished ()), parent, SLOT (thread_dead ()));
  }
};
 
struct Main : public QFrame
{
public slots:
 
  void thread_dead () const
  {
     delete (Thread*) QObject::sender ();
  }
...
 
 

валгринд не ругался (но я с сапрессами гонял)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Апрель 09, 2011, 14:02 »

Сейчас я работаю с потоками так в главном потоке создаю их через new в конце функции run потока вызываю deleteLater().
Это не есть хорошо. т.к.

- нужно быть уверенным что не случилось moveToThread (есть ли у Вас EventLoop в нитке - неизвестно)
- сделав deleteLater и рассчитывая что главная (или др.) удалит, Вы не знаете "когда" - а это может случиться еще до выхода из текущей ф-ции, где Вы полагаете что объект еще валиден

Лучше действовать "кто создал - тот и удалил" или просто удалять "сейчас" или использовать auto_ptr - но не deleteLater, оно здесь не подходит
Записан
like-nix
Гость
« Ответ #5 : Апрель 09, 2011, 17:27 »

Ясно.

Еще вопрос
Где нужно инициализировать(выделять память) члены класса потока непосредственно в run или можно в конструкторе класса потока?
Записан
like-nix
Гость
« Ответ #6 : Апрель 09, 2011, 19:40 »

Прочитал статью http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/ из соседнего топика и уменя появились еще вопросы.

Мне нужно в поток передать массив строк.
Который формируется в гуи. Как мне его правильно передать? Я думаю нужно так

Код:
class Worker : public QObject
{
    Q_OBJECT
public:

Worker(QVector<QString> &vector)
m_vector:(vector)
{

}
public slots:
    void work();
signals:
    void finished();
private:
QVector<QString> m_vector
};

void Worker::work()
{
    // do some work
    emit finished();
}

int main()
{
    QThread thread;
QVector<QString> vector;
…add data to vector

    Worker w(vector);
    w.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &w, SLOT(work()));
    QObject::connect(&w, SIGNAL(finished()), &thread, SLOT(quit()));
    thread.start();
}


Но тогда у меня вопрос сколько копий вектора будет в приложении?
2 или 3.

Записан
like-nix
Гость
« Ответ #7 : Апрель 09, 2011, 19:50 »

Или может быть благодаря implicit sharing если я данные менять не буду то вообще 1 =)
Записан
Akon
Гость
« Ответ #8 : Апрель 09, 2011, 20:04 »

2brankovich:
только вот так:
Код:
...
void thread_dead () const
{
  (Thread*) QObject::sender ()->wait();
  delete (Thread*) QObject::sender ();
}
...

В изначальном варианте (без wait) возможно удаление при использовании (ниже finished() юзается this).

Цитировать
Или может быть благодаря implicit sharing если я данные менять не буду то вообще 1 =)

Да. И используй const ссылку при передаче (const QVector<QString> &vector).
Записан
brankovic
Гость
« Ответ #9 : Апрель 09, 2011, 20:11 »

2brankovich:
только вот так:
Код:
...
void thread_dead () const
{
  (Thread*) QObject::sender ()->wait();
  delete (Thread*) QObject::sender ();
}
...
В изначальном варианте (без wait) возможно удаление при использовании (ниже finished() юзается this).

понятно, спасибо. А не может он сам себя удалить? Если сделать слот suicide () {delete this;}, то я так понимаю всё ещё хуже, а можно как-то правильно сделать, или обязятельно другой поток участвует? И ещё, из-за этого wait гуи подвиснут?

Edit: посмотрел доки, похоже лучше использовать QThreadPool, он сам всё удаляет.
« Последнее редактирование: Апрель 09, 2011, 20:21 от brankovic » Записан
Akon
Гость
« Ответ #10 : Апрель 09, 2011, 20:59 »

suicide () {delete this;}
ИМХО, не стоит такое использовать вообще. К примеру, есть стековый объект и ничто не мешает сделать вызов:
Crazy crazy;
crazy.suicide();  Смеющийся

Из-за wait ожидание должно быть мизерным, т.к. участок кода после finished() и возвращением в ОС небольшой (см. QThreadPrivate::finish(), если не ошибаюсь).

А не может он сам себя удалить?
Понимаю, хотите чего-то элегантного, типа
new MyThread(parameters).start();  // task
и работу сделает, и сам за собой все уберет и ссылок на него не надо  Улыбающийся
Чтобы такое сделать нужно удалять перед самым возвратом в ОС (т.е. к this уже не будет обращений). Нужно падчить сорцы.


 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.411 секунд. Запросов: 19.