Многопоточность: Как обработать данные в векторе, в то время как вектор населяется?
-
02-10-2019 - |
Вопрос
У меня есть однопоточное приложение Linux, которое я хотел бы сделать параллельно. Он читает файл данных, создает объекты и помещает их в вектор. Затем он вызывает компетентный метод (0,5 секунды +) на каждом объекте. Я хочу вызвать метод параллельно с созданием объекта. Пока я посмотрел на Qt и TBB, я открыт для других вариантов.
Я планировал начать нить (ы), пока вектор был пустым. Каждый позвонил бы makeSolids
(ниже), который имеет цикл, который будет работать до тех пор, пока justpdone == true и все объекты в векторе были обработаны. Тем не менее, я N00B, когда дело доходит до резьбы, и я искал готовое решение.
QtConcurrent::map(Iter begin,Iter end,function())
Выглядит очень легко, но я не могу использовать его на векторе, который меняется в размере, может ли я? И как бы я сказал ему ждать больше данных?
Я также посмотрел на TBB Intel, но это выглядело, как моя главная тема, остановная, если бы я использовал parallel_for
или parallel_while
. Отказ Это воняет, поскольку был рекомендован их менеджер памяти (открытый MMGT Cascade имеет плохую производительность при многопоточке).
/**intended to be called by a thread
\param start the first item to get from the vector
\param skip how many to skip over (4 for 4 threads)
*/
void g2m::makeSolids(uint start, uint incr) {
uint curr = start;
while ((!interpDone) || (lineVector.size() > curr)) {
if (lineVector.size() > curr) {
if (lineVector[curr]->isMotion()) {
((canonMotion*)lineVector[curr])->setSolidMode(SWEPT);
((canonMotion*)lineVector[curr])->computeSolid();
}
lineVector[curr]->setDispMode(BEST);
lineVector[curr]->display();
curr += incr;
} else {
uio::sleep(); //wait a little bit for interp
}
}
}
Редактировать: Чтобы обобщить, каков самый простым способом обработки вектора одновременно, что основной поток заполняет вектор?
Решение
Трудно сказать, если вы думаете об этой проблеме глубоко, и есть больше, чем вы пропускаете, или если вы просто думаете об этом, или если вы просто опасаетесь потокости.
Чтение файла и создание объектов быстро; Один метод медленный. Зависимость каждым последовательным CTOR зависит от результата предыдущего ЦТОР - немного странно - но в противном случае нет проблем целостности данных, поэтому, похоже, нет ничего, что необходимо защищать Mutexes и такими.
Почему это сложнее, чем что-то вроде этого (в сыром псевдокоде):
while (! eof)
{
readfile;
object O(data);
push_back(O);
pthread_create(...., O, makeSolid);
}
while(x < vector.size())
{
pthread_join();
x++;
}
Если вы не хотите зацикливаться на присоединениях в своем главе, затем нерените нити, чтобы дождаться их, передавая вектор TID.
Если количество созданных объектов / потоков безумно, используйте пул резьбы. Или поставить счетчик - это цикл создания для ограничения количества потоков, которые могут быть созданы до подключения.
Другие советы
Во-первых, чтобы воспользоваться резьбой, вам нужно найти аналогичные медленные задачи для каждого потока. Вы сказали, что ваша обработка для каждого объекта занимает .5s +, сколько времени ваше создание чтения файлов / объектов? Это может быть легко доливая или тысячная часть этого времени, и в этом случае ваш многопоточный подход собирается производить нелюбиемое преимущество. Если это так, (да, я отвечу на ваш оригинальный вопрос в ближайшее время, если она не стоит), тогда подумайте о одновременном обработке нескольких объектов. Учитывая вашу обработку, требуется довольно некоторое время, создание потока накладные расходы не являются ужасно значительными, поэтому вы можете просто иметь основной материал для чтения / создания объектов создавать новую резьбу и направлять ее при вновь созданном объекте. Основная нить затем продолжает чтение / создание последующих объектов. Как только все объекты будут считываться / созданы, и все потоки обработки запускаются, основной нитью «объединяется» (ждет) рабочие потоки. Если это создаст слишком много потоков (тысячи), затем поместите ограничение на то, насколько далеко допускается основная нить, чтобы получить: он может прочитать / создавать 10 объектов, затем соедините 5, затем прочитайте / создать 10, присоединяйтесь к 10, прочитайте / создать 10, соедините 10 и т. Д. До завершения.
Теперь, если вы действительно хотите, чтобы прочитать / создать, чтобы быть параллельным с обработкой, но обработка должна быть сериализована, то вы все равно можете использовать вышеуказанный подход, но присоединиться после каждого объекта. Это рода странно, если вы разрабатываете это только с таким подходом, но хорошо, потому что вы можете легко экспериментировать с параллелизмом обработки объекта выше.
В качестве альтернативы, вы можете использовать более сложный подход, который просто включает в себя основную нить (чтобы ОС создает, когда ваша программа запускается), и один работник, который должен начать основной поток. Они должны быть скоординированы с помощью Mutex (переменная, обеспечивающая взаимно эксклюзивную, что означает не одновременно, доступ к данным) и переменную условия, которая позволяет рабочему потоку эффективно блокировать до тех пор, пока основной нить не предоставит больше. Условия - переменная METEX и условие - это стандартные условия в потоке POSIX, которые использует Linux, поэтому следует использовать в объяснении конкретных библиотек, которые вы заинтересованы в. Суммара, рабочая нить ждет до тех пор, пока основной прочитан / создает нить Распространяет его сигнал пробуждения, указывающий, что другой объект готов к обработке. Вы можете захотеть иметь счетчик с индексом последнего полностью созданного, готового для обработки объекта, поэтому рабочий ниток может поддерживать его количество обработанных объектов и перемещается вдоль готовых, прежде чем еще раз проверять переменную условию.
@Caleb: совсем - возможно, я должен был подчеркнуть активный потоки. Тема GUI всегда должна считаться одним.