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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Несколько потоков и одна очередь задач.  (Прочитано 9324 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« : Ноябрь 22, 2012, 10:24 »

Доброго времени всем.

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

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

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

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

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

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

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

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

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

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

Кто что думает?  Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Ноябрь 22, 2012, 11:21 »

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

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

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

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

4) Не морочить голову себе и людям - если там хоть какие-то файловые операции, то просто QMutex только с контейнером аккуратнее - напр использовать QDoubleLinkedList
Записан
SimpleSunny
Гость
« Ответ #2 : Ноябрь 22, 2012, 11:29 »

1. В принципе, временем на изъятие из очереди/списка имени файла можно пренебречь.
2. QAtomicInt который хранит позицию первой нерешенной задачи.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 22, 2012, 11:38 »

2. QAtomicInt который хранит позицию первой нерешенной задачи.
Прошу исполнить  Улыбающийся
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Ноябрь 22, 2012, 11:43 »

А если я не использую Qt, а использую std:: ? Улыбающийся

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

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

ArchLinux x86_64 / Win10 64 bit
ssoft
Гость
« Ответ #5 : Ноябрь 22, 2012, 11:46 »

Лучше сделать как проще. А проще сделать (если самому парится с синхронизацией) через семафор, который считает количество заданий.
Очередь опустошается - семафор устанавливается в 0 и начинает блокировать потоки. Появляются задания - счетчик не 0 и потоки начинают работать.
Если время парсинга много больше времени работы семафора не нужно задумываться над атомарной синхронизацией.
Еще лучше посмотреть в сторону QtConcurent (если использовать Qt) и не выдумывать велосипед (мопед и др.).
Записан
SimpleSunny
Гость
« Ответ #6 : Ноябрь 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;
}
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Ноябрь 22, 2012, 11:55 »

Ну, блин, эти все решения на Qt. А я не хотел привязываться к Qt для такой простой консольной программки
и тянуть длл-ки и т.п.

Вопросы:

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

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

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

ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
« Ответ #8 : Ноябрь 22, 2012, 12:02 »

Буст такой же набор библиотек как и Qt.

1. Не сильно вырастет, если не будете тянуть дофига всего из него.
2. Эммм... а стандартный cout вообще не катит, да?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #9 : Ноябрь 22, 2012, 12:04 »

Цитировать
2. Эммм... а стандартный cout вообще не катит, да?

Просто думал, что в бусте все свое, родное, независимо от stl. Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 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);
 
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #11 : Ноябрь 22, 2012, 13:16 »

Ок, спасибо всем.

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

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

ArchLinux x86_64 / Win10 64 bit
Akon
Гость
« Ответ #12 : Ноябрь 22, 2012, 21:20 »

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

Сообщений: 2812


Просмотр профиля
« Ответ #13 : Ноябрь 23, 2012, 09:49 »

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

ArchLinux x86_64 / Win10 64 bit
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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