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

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

Страниц: 1 2 3 [4] 5 6 ... 8   Вниз
  Печать  
Автор Тема: Использование QWaitCondition  (Прочитано 74746 раз)
Bepec
Гость
« Ответ #45 : Декабрь 21, 2012, 14:05 »

Не надо называть мои посты малосодержательными. Я обижаюсь.

Затестил 2000 запусков управляющего потока. Проанализировал файл логов. Результат:
Код:
count  7988   error  0   tmpA  () 
Всего 7988 вызово из воркеров. 0 ошибочных (т.е. в каждых 4 выводах присутствовали только уникальные идентификаторы от 0 до 4). 3 вызова было пропущено всеми потоками (хз как откомментировать Веселый). А в общем нареканий особых нет.

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

Сообщений: 11445


Просмотр профиля
« Ответ #46 : Декабрь 21, 2012, 14:32 »

Затестил 2000 запусков управляющего потока. Проанализировал файл логов. Результат:
Как говорили классики
Цитировать
Тестирование может показать наличие ошибок но не их отсутствие
Тем более что в данном случае тестирование затруднительно. Можно действовать гораздо проще.
Код:
     mutex.lock();
     keyPressed.wait(&mutex);
Увидев такой код Вы можете смело заявлять что это НЕВЕРНО. Потому что, как обсуждали выше, невозможно обеспечить пробуждение на каждый wake. Поэтому надо сначала проверить счетчик, и только если он нулевой - делать wait. Найти "где пробой" конечно интересно (хотя и "выносит моск") - но это совершенно необязательно. Всегда найдется такое хитросплетение ниток когда wake не имеет эффекта.

Так, ну и чего ждем? Изменяем пример чтобы было правильно  Улыбающийся
« Последнее редактирование: Декабрь 21, 2012, 14:38 от Igors » Записан
Bepec
Гость
« Ответ #47 : Декабрь 21, 2012, 14:45 »

А в любом случае где нибудь пробой да произойдёт, насколько я понимаю.
Идеальный в вашем понимании код как должен выглядеть?

Wait с счётчиком больше 0? А смысл?
Ведь инкремент идёт после пробуждения. До него wait будет бесконечным.

Смысл то в том, что счётчик сигнализирует управляющему, что рабочие заняты.

Чуть поясню для себя же.

Рабочий поток
Код:
//Создаём воркеры и управляющий
//count = 0;
//Проверяем счётчик
mutex.lock();
if (count > 0) // условие не выполнится никогда
    keyPressed.wait(&mutex);
//Что мы получаем? Ни один поток не начнёт никогда работать. Ибо в начале count = 0.

В данном примере count не является счётчиком необходимых для выполнения задач.
А является счётчиком работающих потоков.

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

Сообщений: 11445


Просмотр профиля
« Ответ #48 : Декабрь 21, 2012, 19:50 »

А в любом случае где нибудь пробой да произойдёт, насколько я понимаю.
Идеальный в вашем понимании код как должен выглядеть?

Wait с счётчиком больше 0? А смысл?
Ведь инкремент идёт после пробуждения. До него wait будет бесконечным.
Не хочу "размазывать цитаты", отвечу как бы пунктами

- верно, если нет опоры на счетчик, все равно пробьет

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

- "инкремент идет после пробуждения" - а почему это воспринимается как абсолютная истина? Только потому что так написано в букваре? Так возможны ошибки и там (пусть редко). Покажите творческий (а не механический) подход
Записан
Bepec
Гость
« Ответ #49 : Декабрь 21, 2012, 19:54 »

Кхм. Пошла уже демагогия по "абсолютную истину".

- Опора на счётчик не может быть в данном примере. Ибо он сделан с "необязательным" исполнением всех потоков.

- Угум. Приведите код схемы пожалуйста. Копать тему мне (да и другим) не особо хочется.

- Мы как бы разбирали пример. В данном примере инкремент в другом месте бессмысленен. Как бы выйти из этой ситуации?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #50 : Декабрь 21, 2012, 21:20 »

Кхм. Пошла уже ...
Ваш ответ поразительно напоминает другого молодого человека (ну Вы помните), опять-таки куча всяких причин, а 20 (максимум) строк кода - не дождетесь! Чего выкручиваться - ведь "шила в мешке не утаишь"  Улыбающийся

Никогда не надо бояться сказать "да, сейчас я не могу этого сделать - ну не знаю как". Вот последние 2 недели я застрял с adaptive deep shadow sampling - да, ну не знаю как, ищу. Поиск решения - нормальное состояние программиста, остальное извращения.
Записан
Bepec
Гость
« Ответ #51 : Декабрь 22, 2012, 01:24 »

Эмм.. помоему тут как раз поговорка про бревно в своём глазу подойдёт Улыбающийся

Вы предлагаете исправить данный пример, а кода от вас не дождёшься Веселый
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #52 : Декабрь 22, 2012, 12:19 »

Вы предлагаете исправить данный пример, а кода от вас не дождёшься Веселый
Ага, "вот предложил - сам и исправляй" Улыбающийся Ладно, подождем пару деньков, может найдутся смелые
Записан
Bepec
Гость
« Ответ #53 : Декабрь 22, 2012, 14:09 »

Я всё таки не вижу смысла в этом "исправлении". То, что вы предлагаете разительно отличается от текущего примера. То не исправление будет, а вообще другой подход и новый пример.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #54 : Декабрь 24, 2012, 10:35 »

Причешем исходный пример
Код
C++ (Qt)
// thread worker
forever {
    mutex.lock();
    keyPressed.wait(&mutex);
    HandleTask();
    mutex.unlock();
}
 
Код
C++ (Qt)
//control thread
forever {
    getchar();
    mutex.lock();
    CreateTask();
    mutex.unlock();
    keyPressed.wakeAll();
}
 
Оба (HandleTask и CreateTask) могут быть сколь угодно сложными, могут освобождать мутекс и опять захватывать, использовать общие переменные (count) и.т.п. Но с точки зрения QWaitCondition нам совершенно не нужно вникать во все их подробности. Просто добавляем счетчик
Код
C++ (Qt)
// thread worker
forever {
    mutex.lock();
    if (!numTask)
      keyPressed.wait(&mutex);
    if (numTask) {
      --numTask;
      HandleTask();
    }
    mutex.unlock();
}
 
Код
C++ (Qt)
//control thread
forever {
    getchar();
    mutex.lock();
    CreateTask();
    ++numTask;
    mutex.unlock();
    keyPressed.wakeAll();
}
 
Нашего героя смутила переменная с именем "count", он подумал что это тот самый счетчик что и должен использоваться QWaitCondition. В действительности же "в огороде бузина, а в Киеве дядька"   Улыбающийся
Записан
Bepec
Гость
« Ответ #55 : Декабрь 24, 2012, 10:55 »

Кхм. У вас не "причёсанный" пример.

Вы вырезали проверку на наличие работающих потоков.
И в вашем случае работать будет только 1 поток.

Проще выражаясь вы убили многопоточность, у вас 1 производитель, 1 потребитель, и радуетесь этому?

Если непонятно, то в один момент времени у вас будет выполняться лишь 1 воркер. Многопоточность убита.


Подвожу краткую выжимку:

Что сделал Igors:
Удалил проверку на наличие работающих потоков.
Убил многопоточность.

Что получилось:
Получился один воркер и ненужный контрольный поток.
Ненужный потому, что с таким же успехом от него можно отказаться и функционал не изменится.

PS я вот одного не пойму, зачем вы убили многопоточность? Или я чего то не вижу и воркеры могут выполнять HandleTask параллельно?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #56 : Декабрь 24, 2012, 11:01 »

PS я вот одного не пойму, зачем вы убили многопоточность? Или я чего то не вижу и воркеры могут выполнять HandleTask параллельно?
Конечно могут. Никого я не убивал - просто перенес куски кода в ф-ции HandleTask и CreateTask, все работает как раньше - только теперь задачи не пропускает  Улыбающийся
Записан
Bepec
Гость
« Ответ #57 : Декабрь 24, 2012, 12:05 »

Код:
// thread worker
forever {
     mutex.lock();
     if (!numTask)
       keyPressed.wait(&mutex);
     if (numTask) {
       --numTask;
       HandleTask();// Вот тут выполняется задача.
     }
     mutex.unlock();
}

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

Код:
//worker 1
lock
функция
unlock
//worker 2
lock
функция
unlock
//worker 3
lock
функция
unlock

А нужно
Код:
lock-unlock // worker'ы прибавили счётчик, освободили мутекс.
//worker 1  worker 2   worker 3
функция    функция   функция
lock-unlock // worker'ы убавили счётчик, освободили мутекс.

В вашем примере нет многопоточного выполнения задачи. Есть простое последовательное выполнение. Мутекс ваш в воркере не даёт им параллельно выполнять задачу.

В примере же ассистента происходит параллельное выполнение ёмкой функции. Затраты на мутекс лок/анлок незначительны по сравнению с задачей.

Хотя нет, даже не так. Данный подход как раз и нужен для параллельного выполнения ресурсоёмких задач.

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

Сообщений: 11445


Просмотр профиля
« Ответ #58 : Декабрь 24, 2012, 12:15 »

PS покажите мне параллельность в вашем примере.
Код
C++ (Qt)
void HandleTask( void )
{
   ++count;
    mutex.unlock();  // мутекс освобождается, др потребители могут работать (если для них есть задачи)
 
    do_something();  
 
    mutex.lock();
    --count;
}
 
Записан
Bepec
Гость
« Ответ #59 : Декабрь 24, 2012, 13:08 »

Вах, на виду то всё было, а я ж слепой да не заметил Улыбающийся

И опять появляется некое count? Или у вас опечаточка с numTask?
Записан
Страниц: 1 2 3 [4] 5 6 ... 8   Вверх
  Печать  
 
Перейти в:  


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