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

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

Страниц: 1 2 3 [4] 5 6 ... 17   Вниз
  Печать  
Автор Тема: Igors, это ты? :)  (Прочитано 132479 раз)
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #45 : Август 28, 2018, 08:01 »

Мимо крокодил)), но добавлю свои пять копеек.
На мой взгляд совершенно не корректно так вот сравнивать два инструмента без акцента на особенностях их применения.
Любая задача решается с помощью того и другого инструмента, при этом самыми разными способами. В итоге обсуждение перейдет в русло - какой способ решения лучше.

В теме предлагается рассмотреть академическую задачу Producer/Consumer, имеющую большое прикладное значение. Количество способов реализации с учетом всяких частных случаев огромно.

Представленное решение на std использует глобальные переменные и жесткую взаимосвязь между Producer и Consumer. Для решения конкретной задачи подойдет, почему бы и нет. Но практически также можно всё написать и на Qt.

Реализация Producer/Consumer с помощью механизма signal/slot преследует цель - исключить зависимости между Producer и Consumer, для возможности их независимого повторного использования в любом сочетании.
Можно, конечно, отметить, что реализация механизма signal/slot в Qt кособокая - требует наследование, нарушает принципы инкапсуляции, использует генерацию кода, потоко зависимая и т.п.
Но порог вхождения в Qt достаточно низкий, функционал богатый, поэтому инструмент имеет большое распространение.

Думаю, что не стоит сравнивать "синее с кислым", а лучше изучить и то и другое, а потом уже делать обоснованный (все-равно субъективный) выбор того или иного инструмента при решении конкретных задач.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #46 : Август 28, 2018, 09:54 »

Реализация Producer/Consumer с помощью механизма signal/slot преследует цель - исключить зависимости между Producer и Consumer, для возможности их независимого повторного использования в любом сочетании.
Но это же наколенный пример. Улыбающийся
Можно написать еще более независимую очередь, в которую можно добавлять любые задания и дожидаться их появления. А использовать ее можно везде: от передачи заданий между двумя потоками и до реализации пула потоков. Без всяких сигналов/слотов.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #47 : Август 28, 2018, 11:25 »

Но это же наколенный пример. Улыбающийся
Можно написать еще более независимую очередь, в которую можно добавлять любые задания и дожидаться их появления. А использовать ее можно везде: от передачи заданий между двумя потоками и до реализации пула потоков. Без всяких сигналов/слотов.

Я про тоже самое.  Смеющийся Сигнал/слот, очереди, подписки, последовательный/параллельный, пул потоков/один поток, синхронный/асинхронный, блокированный/неблокированный и т.п. Алгоритмов реализации много.
Чтобы адекватно сравнить два инструмента, их нужно рассматривать в одинаковом алгоритме. Иначе будет "битва подходов", где сами инструменты почти ни при чем.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #48 : Август 28, 2018, 11:26 »

А накидайте - ка что-нить реально рабочее, а не наколенное.. Мож пригодится. Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #49 : Август 28, 2018, 15:50 »

Код:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
 
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
 
void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});
 
    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";
 
    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";
 
    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}
 
int main()
{
    std::thread worker(worker_thread);
 
    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();
 
    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';
 
    worker.join();
}
По-моему этот пример так же неверен как и этот

Допустим thread стартует с солидной задержкой и главная нитка успела выполнить  cv.notify_one() - но на мутексе еще никто не ждет. Или worker был вытеснен и не успел с cv.wait, Тогда побудка notify_one не имеет эффекта. А когда worker наконец получит управление и отдастся на мутекс - его будет некому будить.
Или я где-то ошибаюсь?

ошибаетесь. код безупречен.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #50 : Август 28, 2018, 17:24 »

Но это же наколенный пример. Улыбающийся
Можно написать еще более независимую очередь, в которую можно добавлять любые задания и дожидаться их появления. А использовать ее можно везде: от передачи заданий между двумя потоками и до реализации пула потоков. Без всяких сигналов/слотов.

Очередь событий называется Подмигивающий
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #51 : Август 28, 2018, 17:50 »

Очередь событий называется Подмигивающий
Ну это очень общее название. Я бы это скорее назвал очередью задач. Улыбающийся
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #52 : Август 28, 2018, 18:16 »

Очередь событий называется Подмигивающий
Ну это очень общее название. Я бы это скорее назвал очередью задач. Улыбающийся

всегда думал - что обычный тред-пул.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #53 : Август 28, 2018, 18:21 »

всегда думал - что обычный тред-пул.
В тред пуле, как раз, потоки из очереди задач задачи и достают. Очередь задач как бы часть пула потоков.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #54 : Август 29, 2018, 09:07 »

А, там прекондишн проверяется через эти модные лямбды. Ну ок.
Да, тоже не заметил  Улыбающийся

А накидайте - ка что-нить реально рабочее, а не наколенное.. Мож пригодится. Улыбающийся
Схема одна и та же, другой нет, ее надо просто зазубрить

В теме предлагается рассмотреть академическую задачу Producer/Consumer, имеющую большое прикладное значение. Количество способов реализации с учетом всяких частных случаев огромно.

Представленное решение на std использует глобальные переменные и жесткую взаимосвязь между Producer и Consumer. Для решения конкретной задачи подойдет, почему бы и нет. Но практически также можно всё написать и на Qt.
Реализация std (вернее выбранный примитив) пожалуй самая сложная/трудная. Попробуйте напр сделать то же но в цикле - и уже придется чесать репу. В то же время слот/сигналом не составляет труда, а если хочется на примитивах - есть прекрасный (Q)Semaphore

Можно, конечно, отметить, что реализация механизма signal/slot в Qt кособокая - требует наследование, нарушает принципы инкапсуляции, использует генерацию кода, потоко зависимая и т.п.
Что это за мода появилась хаять Qt, причем "в самых общих чертах"?  Улыбающийся Даже если согласиться с "кособокостью" - это невысокая цена за удобство использования. Даже знать базовые примитивы синхронизации необязательно, есть средства удобнее/приятнее

Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #55 : Август 29, 2018, 09:57 »

Реализация std (вернее выбранный примитив) пожалуй самая сложная/трудная. Попробуйте напр сделать то же но в цикле - и уже придется чесать репу.
Ну это вам придется чесать репу, а человеку знающему как работают условные переменные - не придется. Потому, что эта конструкция для циклов как раз и приспособлена. Улыбающийся
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #56 : Август 29, 2018, 13:23 »

всегда думал - что обычный тред-пул.
В тред пуле, как раз, потоки из очереди задач задачи и достают. Очередь задач как бы часть пула потоков.

дык. о том и речь.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #57 : Август 29, 2018, 14:40 »

Ну это вам придется чесать репу, а человеку знающему как работают условные переменные - не придется. Потому, что эта конструкция для циклов как раз и приспособлена. Улыбающийся

Вот не надо тут "ляля" про условные переменные. То, что в стд засунули лямбду как проверку предусловия, конечно, удобно и избавляет от ошибок, но лямбды появились только в 11х плюсах, а для "человека, знающего, как работают условные перменные" горааааздо дольше примером были QWaitCondition или pthread_cond_wait где никаких лямбд не было и прекондишн надо было проверять руками. На что мы с Igors и напоролись - не увидели малюсенький вызов лямбды.

На самом деле бесят апологеты стд которым НАКОНЕЦ-то дали какое-то АПИ которым они везде тыкают как будто это омагад какое изобретение.
Ну да, std::vector лучше QVector из-за мув-семантики, которой не было когда писался QVector, а поменять теперь QVector нельзя из-за совместимости (как и сделать в std::vector signed size_t для индекса или сделать struct {key, value} вместо богомерзкой пары в std::map). Я же не троллю вас тем что у вас для строки надо писать std::string::npos вместо банальной -1.
Стд тоже далеко не идеально, взять те же футуры или строки или регэкспы или... Но чертова совместимость мешает это всё исправить.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #58 : Август 29, 2018, 15:33 »

Авварон, а я именно про простые условные переменные и говорю. Улыбающийся
Лямбды это просто синтаксический, я до сих пор этот цикл пишу руками и это не мешает мне использовать условные переменные в циклах. Улыбающийся
« Последнее редактирование: Август 29, 2018, 15:55 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #59 : Август 29, 2018, 15:40 »

То, что в стд засунули лямбду как проверку предусловия, конечно, удобно и избавляет от ошибок,
Не могу с Вами согласиться.
Цитировать
cv.wait(lk, []{return ready;});
Цитировать
while (!ready)
  cv.wait(lk);
Да, первый вариант экономит строку, но ценой "запоминания". И вот за что я не люблю std - он весь прямо-таки засыпан таким калом. Немногие нужные полезные вещи просто тонут в таких "экономиях 1-2 строк" на которые и уходит > 90% энергии изучающего. Впрочем есть люди которые стремятся запомнить как можно больше, им это в кайф.

Однако вернемся к теме. Задача что я предложил - да, относится к категории производитель-потребитель, но есть особенность - операции должны выполняться строго последовательно, сначала одна нитка читает, потом вторая пишет. Очередь и/или событийный цикл для этого, строго говоря, избыточны. Наиболее естественной мне представляется реализция на семафорах
Код
C++ (Qt)
#include <QtWidgets>
 
QString data;
QSemaphore semWork(0), semMain(1);
 
class MyThread : public QThread {
void run( void )
{
while (true) {
semWork.acquire();
if (!data.size())
break;
data += " proccesed";
qDebug() << data;
semMain.release();
}
}
};
 
int main()
{
MyThread worker;
worker.start();
 
const int numTest = 5;
for (int i = 0; i < numTest + 1; ++i) {
semMain.acquire();
if (i == numTest)
data.clear();
else
data = "data " + QString::number(i + 1);
semWork.release();
}
   worker.wait();
}
 
Никаких заморочек, знай себе открывай-закрывай семафоры, все совершенно естественно. Но увы, зная собеседников, уверен что это будет охаяно, ведь в великом std такого нет...
Записан
Страниц: 1 2 3 [4] 5 6 ... 17   Вверх
  Печать  
 
Перейти в:  


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