Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: kuzulis от Ноябрь 22, 2012, 10:24



Название: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 22, 2012, 10:24
Доброго времени всем.

Обращаюсь ко всем Гуру многопоточного программирования кто на этом съел собаку.

Делаю консольный патчер для возможности переноса уже установленного Qt в любую другую директорию,
или просто для исправления некоторых бинарных файлов (например qdoc для Qt5-betaX) или тестовых (в перспективе).

Итак, имеется некая функция, которая патчит заданный бинарный файл:

Код:
static void patch()
{
    // do
}

Есть набор бинарных файлов (набор полных путей к файлам) для патчинга.

Как планирую сделать:

1. При старте приложения набор заданных имен файлов один раз помещается в некую очередь или список.
Пусть будет типа queue<string>. Доступ к очереди защищается при помощи семафора.

2. Стартую оптимальное кол-во потоков. Каждый поток пытается обратиться к очереди и
изъять из нее задачу - т.е. имя файла и пропатчить его. Когда поток пропатчивает файл
он обращается к очереди (или списку) за новой задачей или, если задач больше нет (очередь пуста)
то поток завершается.

Так вот, можно ли как-то это дело оптимизировать без использования семафора/мьютекса?
Или тут без вариантов?

В принципе, временем на изъятие из очереди/списка имени файла можно пренебречь,
т.к. это очень быстро, поэтому семафор не должен сильно задерживать потоки.

Кто что думает?  :)


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: Igors от Ноябрь 22, 2012, 11:21
Так вот, можно ли как-то это дело оптимизировать без использования семафора/мьютекса?
Или тут без вариантов?
Вариантов море

1) Без всяких мутексов (lock-free) через QAtomicPointer::testAndSetAcquire

2) Использовать быстрый нативный атомарный лок (на линухе вроде pthread_spin_lock)

3) Сделать свой атомарный лок на QAtomicInt (5 мин)

4) Не морочить голову себе и людям - если там хоть какие-то файловые операции, то просто QMutex только с контейнером аккуратнее - напр использовать QDoubleLinkedList


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: SimpleSunny от Ноябрь 22, 2012, 11:29
1. В принципе, временем на изъятие из очереди/списка имени файла можно пренебречь.
2. QAtomicInt который хранит позицию первой нерешенной задачи.


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: Igors от Ноябрь 22, 2012, 11:38
2. QAtomicInt который хранит позицию первой нерешенной задачи.
Прошу исполнить  :)


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 22, 2012, 11:43
А если я не использую Qt, а использую std:: ? :)

В принципе, нашел что-то похожее тут http://progsch.net/wordpress/?p=81

UPD: Вот, блин, это ж только для C++11, значит придется писать на Qt и тянуть зависимости :(


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: ssoft от Ноябрь 22, 2012, 11:46
Лучше сделать как проще. А проще сделать (если самому парится с синхронизацией) через семафор, который считает количество заданий.
Очередь опустошается - семафор устанавливается в 0 и начинает блокировать потоки. Появляются задания - счетчик не 0 и потоки начинают работать.
Если время парсинга много больше времени работы семафора не нужно задумываться над атомарной синхронизацией.
Еще лучше посмотреть в сторону QtConcurent (если использовать Qt) и не выдумывать велосипед (мопед и др.).


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: SimpleSunny от Ноябрь 22, 2012, 11:47
Прошу исполнить  :)

Если задач не сильно много и их (или указатели на них) можно держать в памяти до конца и они не меняются (как было у ТС).
Код
C++ (Qt)
QAtomicInt firstTask = 0;
QVector <Task> tasks;
...
bool getTask(Task &t)
{
int max = tasks.size();
int current = firstTask.fetchAndAddRelease(1);
 
if (current >= max)
return false;
 
t = tasks[current];
return true;
}


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 22, 2012, 11:55
Ну, блин, эти все решения на Qt. А я не хотел привязываться к Qt для такой простой консольной программки
и тянуть длл-ки и т.п.

Вопросы:

1. А если я буст поробую использовать, то сильно вырастет размер бинарика?
2. Есть ли в бусте что-то вроде boost::cout ?

Или не париться с потоками, и замутить на stl, обрабатывая файлы тупо по-порядку ?

ЗЫ: С бустом дела не имел.


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: Bepec от Ноябрь 22, 2012, 12:02
Буст такой же набор библиотек как и Qt.

1. Не сильно вырастет, если не будете тянуть дофига всего из него.
2. Эммм... а стандартный cout вообще не катит, да?


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 22, 2012, 12:04
Цитировать
2. Эммм... а стандартный cout вообще не катит, да?

Просто думал, что в бусте все свое, родное, независимо от stl. :)


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: Igors от Ноябрь 22, 2012, 13:10
Ну, блин, эти все решения на Qt. А я не хотел ..
Предупреждать, блин, надо чтобы воздух не гонять. Ладно

1)  Возможно QAtomicInt и не потребует никаких либов - все на хедерах.

2) Если gcc то "достаточно одной таблетки", напр __sync_fetch_and_add, дальше меняете 2 строки в примере SimpleSunny

Код
C++ (Qt)
// QAtomicInt firstTask = 0;
volatile int firstTask = 0;
 
...
// int current = firstTask.fetchAndAddRelease(1);
int current = __sync_fetch_and_add(&firstTask, 1);
 


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 22, 2012, 13:16
Ок, спасибо всем.

Буду делать на stl + boost, т.к. возможно мультиплатформенное использование с
разными компиляторами (которые не поддерживают C++0x).

А вместо mutex/semaphore наверное использую что-то вроде atomic int.


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: Akon от Ноябрь 22, 2012, 21:20
имхо, лок-фри для такой задачи не нужен, поскольку время обработки задания велико. В бусте тоже много примитивов синхронизации: мьютексы и т.д.


Название: Re: Несколько потоков и одна очередь задач.
Отправлено: kuzulis от Ноябрь 23, 2012, 09:49
Ок. Спасибо всем. Я передумал, сделаю на чистом stl без потоков. Не стоит оно того, чтобы потоки лепить. :)