Как стать автором
Обновить

Комментарии 23

Чтобы те, кому интересно, могли следить за изменениями в статья, я в этом комментарии буду описывать все изменения в тексте.
Комментарий можно редактировать только первые три минуты после его публикации, так что не выйдет :)
Изменения в тексте принято помечать UPD прямо в тексте, также к вашим услугам тег <s> который позволяет делать так
Это да, но: допустим, мне понравилась статья. По ней пошла дискуссия, в которой принимает участие и автор тоже. И вот, он вносит правки, а мне они также интересны. Мне было бы очень удобно, если бы он в одном месте перечислял бы все свои правки — иначе я должен периодически просматривать весь текст в поисках оных
Спасибо!
А зачем вообще нужна такая сущность, как ThreadedObject? Я считаю, потоки должны быть отделены от объектов. Single responsibility же.
Также, как и сборка мусора в памяти: ThreadedObject гарантирует удаление объекта. А может и не гарантировать, если так удобно клиенту.
Для того, чтобы гарантировать удаление, уже есть умные указатели. (А удаление через deleteLater вообще ничего никому не гарантирует, потому что работает только если запущен event loop.)
Как правильно использовать QThread

class Worker : public QObject {
    Q_OBJECT
 
public:
    Worker();
    virtual ~Worker();
 
public slots:
    void process();
 
signals:
    void finished();
    void error(QString err);
 
private:
    // add your variables here
};


// --- CONSTRUCTOR ---
Worker::Worker() {
    // you could copy data from constructor arguments to internal variables here.
}
 
// --- DECONSTRUCTOR ---
Worker::~Worker() {
    // free resources
}
 
// --- PROCESS ---
// Start processing data.
void Worker::process() {
    // allocate resources using new here
    qDebug("Hello World!");
    emit finished();
}


QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();


И все. Не усложняйте шаблонами там, где это не требуется.
Нет. Это неправильный метод. Если вам нужно выполнить единичную работу, то можно использовать пул потоков (его наконец-то починили) + runnable, или Qt concurrent, или переопределить метод run у потока.

Если вы создаете некоторый сервис, который будет работать в отдельном потоке, получая сигналы от клиентов, то останавливать сам себя он не сможет, это должен делать контроллер сервиса.
Вот как раз переопределять метод run у QThread — это и есть неправильный способ, который, тем не менее, получил самое широкое распространение, и именно для исправления этой ситуации и была написана статья по ссылке:
This should immediately show why the recommended way of using QThreads in the documentation, namely to sub-class it and implement your own run() function, is very wrong.
Не нужно путать 2 варианта использования потока, которые я описал выше. Для второго варианта, это действительно неправильный способ, а для первого — ок.

Я понимаю, что теперь все прочитали Qt threads you're doing it wrong и носятся вокруг него, но есть и альтернативные мнения.
>Не нужно путать 2 варианта использования потока, которые я описал выше

В первую очередь не нужно путать «использование потоков» и «использование QThread». Я говорю и изначально говорил о последнем и только о последнем, поэтому вариантов с QThreadPool или QtConcurrent даже не касался.

Что касается «альтернативного мнения» — вы прочитайте внимательно статью-то. Она кагбэ слегка ортогональна тому, что написано по моей ссылке, там совсем другой подход рассматривается и оспаривается.
ну обычно, если речь не идет о лабораторной работе, нужно все-таки решить задачу, а не использовать feature %featurename%, так что первое возражение не принимается.

Что касается второго, то весь шум пошел от статьи QThread: you're doing it wrong в блоге Qt. А то что я привел — собственно реакция на эту статью.
Я извиняюсь, но это не «возражение», это изначальная постановка задачи: «если уж мы используем QThread, то делать это нужно следующим образом». По крайней мере я подразумевал именно такую постановку задачи, и довольно четко это указал. И решение в статье, как вы сами видите, использует именно QThread.
Так что не вы «не принимаете мое возражение», это я не принимаю вашу измененную задачу (подразумевающую множество решений в зависимости от неизвестных дополнительных условий).

>Что касается второго, то весь шум пошел от статьи QThread: you're doing it wrong в блоге Qt. А то что я привел — собственно реакция на эту статью.

То есть вы привели «ответ на статью X» в качестве ответа на статью Y, которая довольно сильно отличается от статьи X? Вам не кажется, что тут что-то не так?
ок, вы можете делать, как хотите, а я буду делать так, как эффективнее всего.

та ссылка, которая у вас приведена — собственно разъяснение в деталях статьи QThread: you're doing it wrong.
>ок, вы можете делать, как хотите, а я буду делать так, как эффективнее всего.

Вы удивитесь, но я могу дословно процитировать эту фразу вам в ответ :)

Хорошего дня.
Я раньше думал, что так оно и вправду лучше. Но сравните Вашу и мою реализацию: у Вас объект создается ДО создания потока — и поэтому потом необходимо его moveToThread. У меня же он изначально создается в новом потоке. Я думаю, что по-моему эффективней.
Это, в обшем, не важно. Потому что если скорость создания потока становится важна, то у вас есть более серьезные проблемы.
Уж не знаю, сколько микросекунд вы выиграете на перемещении объекта в поток, но за приведенный мной вариант есть как миниму 2 аргумента:
1) Он более поддерживаемый. Просто сравните объем кода для прочтения и понимания другим человеком.
2) Ваш шаблон (как и все шаблоны) будет генерировать отдельный класс на каждый класс-параметр, и при малейшем изменении в вашем классе будет происходить перекомпиляция всего зависимого кода (я даже не говорю о размере бинарника и занимаемой памяти, т.к. это не всегда настолько критично).
Не усложняйте шаблонами там, где это не требуется

Как по мне, то в данном случае это очень в тему — получаем очень удобное решение для многоразового использования.
А чем вам приведенное мной решение не «многоразовое»? Затолкайте Worker в библиотеку, добавьте ему виртуальный protected метод, в котором будет сама логика, спрячьте кусок кода с созданием QThread и соединением сигналов в отдельный «запускающий» метод — и на стороне клиентского кода использование будет заключаться в наследовании от Worker (чисто для переопределения метода с логикой — минимум дополнительного кода), создании его экземпляра и вызове запускающего метода.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации