Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ С\С++ _ Потоконезависимые очереди

Автор: AD 7.11.2011, 10:28

Есть ли в библиотеках Qt, boost реализация потоконезависимых очередей? Можно ли применить QList? Если нет, есть ли в инете подобное? Поискал сам, пока ничего путного не видел. Может быть кто-то уже видел что-то подобное?

Автор: BRE 7.11.2011, 11:44

Что имеется ввиду под "потоконезависимые"?
QList использовать можно, если к одному экземпляру списка нужен доступ на запись из разных потоков, то придется использовать механизмы синхронизации.
Что вообще требуется от этой очереди?

Автор: AD 7.11.2011, 12:02

Цитата(BRE @ 7.11.2011, 12:44) *
Что имеется ввиду под "потоконезависимые"?
QList использовать можно, если к одному экземпляру списка нужен доступ на запись из разных потоков, то придется использовать механизмы синхронизации.
Что вообще требуется от этой очереди?

Насколько я понимаю, под потоконезависимыми подразумевается, скорее всего, когда механизм синхронизации происходят внутри реализации очереди, хотя я лично смутно это себе представляю. Но такое в принципе возможно, когда синхронизация происходит внутри реализации?

Автор: BRE 7.11.2011, 12:23

Цитата(AD @ 7.11.2011, 13:02) *
Но такое в принципе возможно, когда синхронизация происходит внутри реализации?

Конечно возможно. Но для этого нужно определиться какими свойствами эта очередь должна обладать.

Автор: AD 7.11.2011, 12:45

Цитата(BRE @ 7.11.2011, 13:23) *
Конечно возможно. Но для этого нужно определиться какими свойствами эта очередь должна обладать.

Например, что за свойства такие особенные? Насколько я знаю, ее определение из вики вполне оправдывает все ее особенности:
Цитата
О́чередь — структура данных с дисциплиной доступа к элементам «первый пришёл — первый вышел» (FIFO, First In — First Out). Добавление элемента (принято обозначать словом enqueue — поставить в очередь) возможно лишь в конец очереди, выборка — только из начала очереди (что принято называть словом dequeue — убрать из очереди), при этом выбранный элемент из очереди удаляется.

Ну а то, что реализация может быть на связном списке, на массиве или еще как-то, то это я знаю!

Автор: Iron Bug 7.11.2011, 12:45

в бусте есть библиотека intrusive - там реализованы потокобезопасные на определённом уровне (http://www.boost.org/doc/libs/1_46_0/doc/html/intrusive/thread_safety.html) контейнеры указателей. удобная и исключительно быстрая штука. но тоже не всё полностью.
кроме того, есть interprocess, там реализовано множество разных контейнеров для обмена между процессами, но можно юзать где угодно. это медленее и, вообще говоря, неявно включает работу с файлами.

Автор: BRE 7.11.2011, 13:09

Цитата(AD @ 7.11.2011, 13:45) *
Например, что за свойства такие особенные?

Опиши, как ты с ней будешь работать из разных потоков? :)
Например, один поток помещает в очередь задания, а несколько других потоков их вынимают и выполняют или несколько потоков туда помещают данные, а один поток их сохраняет в базу, или... ;)

Автор: Алексей1153 7.11.2011, 13:17

без синхронизации никуды )

Автор: AD 7.11.2011, 13:31

Цитата(BRE @ 7.11.2011, 14:09) *
Опиши, как ты с ней будешь работать из разных потоков? :)

Вот так будет работать:
Цитата
Например, один поток помещает в очередь задания, а несколько других потоков их вынимают и выполняют ...

Автор: BRE 7.11.2011, 13:50

На соседнем форуме обсуждали. Одна из тем: http://www.prog.org.ru/index.php?topic=14426.msg95463#msg95463

Автор: AD 9.11.2011, 17:30

Цитата(BRE @ 7.11.2011, 14:50) *
На соседнем форуме обсуждали. Одна из тем: http://www.prog.org.ru/index.php?topic=14426.msg95463#msg95463

Спасибо еще раз. Есть еще один небольшой вопрос - дополнение к тому, что я увидел на prog.org по указанной ссылке. Надо ли взводить семафор (semaphore.acquire()), если я хочу проверить очередь на пустоту (вед в основе список QList) или узнать размер очереди?

Автор: BRE 9.11.2011, 17:45

Не нужны там семафоры (для другого они заточены), ну да ладно. :)
И в первом и во втором случае нужно блокировать доступ к QList.

Автор: AD 9.11.2011, 18:19

Цитата(BRE @ 9.11.2011, 18:45) *
Не нужны там семафоры (для другого они заточены), ну да ладно. :)

Не ладно. Буду благодарен, если раскроешь суть. И еще вопросик. Как на русский переводится термин "wait condition" (дословно-то я знаю, состояние ожидания)?

Автор: BRE 9.11.2011, 19:05

Чаще всего встречал перевод "условные переменные".

Автор: AD 10.11.2011, 10:19

Ага. Ну тут еще вопросы.
Смысл программы следующий: в главном потоке мы заполняем очередь запросов, в дополнительном - происходят вычисления и результаты попадают в очередь результатов. Исходя из приведенного на прог.орг примера сделал функции проверки на пустоту и размер следующими:

/// Пpoвepka на пустую очередь
bool ReqQueue::isEmpty()
{
    QMutexLocker locker(&_mtx);
    while(_req_list.isEmpty())
        _cond.wait(&_mtx, 300);

    return _req_list.isEmpty();
}

/// Pазмер очередu
int ReqQueue::size()
{
    QMutexLocker locker(&_mtx);
    while(_req_list.isEmpty())
        _cond.wait(&_mtx, 300);

    return _req_list.size();
}

Но это как-то не так. При проверке на пустоту цикл while не заканчивается. Как это поправить корректно? На сколько я понял из обсуждения на то форуме, цикл нужен, но тогда какой?

Автор: BRE 10.11.2011, 10:26

Не нужно ждать условную переменную. Она нужна в рабочих потоках, что бы усыпить поток на время когда нет работы.

bool ReqQueue::isEmpty()
{
    QMutexLocker locker(&_mtx);
    return _req_list.isEmpty();
}

/// Pазмер очередu
int ReqQueue::size()
{
    QMutexLocker locker(&_mtx);
    return _req_list.size();
}


Автор: AD 10.11.2011, 14:22

Из главного потока запустил дополнительный. В дополнительном у меня вечный цикл (forever) - памяти жрет 50%. Есть возможность, не отменяя цикла forever сделать так, чтобы память не жралась безмерно?

С потоками уже не раз работал, но еще ни разу не использовал forever в доп. потоке, потому такие вопросы и встают.

Пока что делаю так (память жрет):

/// Запуск потока вычисления
void CalcThread::run()
{
    forever
    {
        wait(_sec * TO_MILLISEC);
        if(QueueRequests.isEmpty())
            continue;

        Request request(QueueRequests.takeRequest());
        int error_code;
        double result = doOperation(request.type_work, request.first_operand, request.second_operand, error_code);
    }
}

Автор: BRE 10.11.2011, 15:27

"Память жрет" это ты про "процессор жрет"? :)
Что такое функция wait, как она определена?
А лучше ты все покажи. ;)

Автор: AD 10.11.2011, 15:30

Цитата(BRE @ 10.11.2011, 16:27) *
"Память жрет" это ты про "процессор жрет"? :)
Что такое функция wait, как она определена?
А лучше ты все покажи. ;)

Да, проц жрет. wait - функция QThread. Так у меня это одна функция в Qthread. :)

Автор: Iron Bug 10.11.2011, 15:38

дык, в безусловном цикле крутится - потому и жрёт. любой поллинг жрёт проц.
тебе же про условные переменные говорили - вот и примени их, чтобы было условие, что в очереди что-то появилось, а в рабочем потоке - ожидание этого условия.

Автор: AD 10.11.2011, 15:47

А вот так в поток не попадаю вторично:

/// Запуск потока вычисления
void CalcThread::run()
{
    if(!QueueRequests.isEmpty())
    {
                     wait(_sec * TO_MILLISEC);
        Request request(QueueRequests.takeRequest());
        int error_code;
        double result = doOperation(request.type_work, request.first_operand, request.second_operand, error_code);
    }

    exec();
}

Поток запускаю в главном потоке в конструкторе.

Автор: BRE 10.11.2011, 16:19

Пытаешься написать методом научного тыка? :)

Автор: AD 10.11.2011, 16:26

Цитата(BRE @ 10.11.2011, 17:19) *
Пытаешься написать методом научного тыка? :)

Да нет. Просто никак не могу понять, зачем этот exec(), если я не возвращаюсь в поток? Понятное дело, что после нескольких попыток в итоге сделаю по другому, но хотел разобраться, как заставить вернуться в функцию run правильно?

Автор: BRE 10.11.2011, 16:36

exec никуда не возвращает, она просто запускает цикл обработки событий для данного потока. Выйти из этого цикла позволяет метод quit или exit класса QThread.

Автор: AD 10.11.2011, 16:40

Цитата(BRE @ 10.11.2011, 17:36) *
exec никуда не возвращает, она просто запускает цикл обработки событий для данного потока. Выйти из этого цикла позволяет метод quit или exit класса QThread.

А... Начинает доходить. Т.е. по сути exec() запустить в теле run(). А затем с помощью сигналов и слотов выполнить нужные мне действия. Так ведь можно решить?

Автор: BRE 10.11.2011, 16:58

Цитата(AD @ 10.11.2011, 17:40) *
Цитата(BRE @ 10.11.2011, 17:36) *
exec никуда не возвращает, она просто запускает цикл обработки событий для данного потока. Выйти из этого цикла позволяет метод quit или exit класса QThread.

А... Начинает доходить. Т.е. по сути exec() запустить в теле run(). А затем с помощью сигналов и слотов выполнить нужные мне действия. Так ведь можно решить?

Да можно и так, только есть ли смысл постоянно крутить цикл обработки событий (который много чего делает) только для того, что бы получить очередное задание. :rolleyes:

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)