Re: Вопрос по многопоточности для C++ проекта
От: chaotic-kotik  
Дата: 05.07.16 10:28
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Собираюсь делать новый проект на C++, при этом планирую активно

AG>применять распарраллеливание обработки данных за счёт многопоточности.

AG>Какие могут быть соображения по выбору?


В данном случае выбор не важен. Важны алгоритмы. Если параллельный алгоритм часто ждет на мьютексе, то реализация мьютекса не очень важна, на самом то деле. Он будет медленно работать. Поэтому я бы задумался прежде всего об алгоритмах и о том как избежать синхронизации, насколько это возможно. Конкретный инструмент я бы выбирал в зависимости от задачи, если у вас data-parallel алгоритмы, то стоит использовать OpenMP, например, а не явную синхронизацию, ну а если это серверное приложение — то стоит использовать то что предоставляет ваш тулкит для построения серверов (strands в boost.asio например).
Re[2]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 10:33
Оценка:
CK>Если параллельный алгоритм часто ждет на мьютексе, то реализация мьютекса не очень важна, на самом то деле
Зависит от задачи. Если время, которое будет затрачено на разделяемую задачу, сравнительно небольшое, то обращаться каждый раз к ядру, например, может быть слишком расточительно.
Re: Вопрос по многопоточности для C++ проекта
От: so5team https://stiffstream.com
Дата: 05.07.16 11:18
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Собираюсь делать новый проект на C++, при этом планирую активно

AG>применять распарраллеливание обработки данных за счёт многопоточности.

Многопоточность -- это инструмент, который используется в двух сильно разных направлениях:

1. Parallel computing. Т.е. использование распараллеливания вычислений на все доступные ядра для уменьшения общего времени решения задачи. При этом, вероятно, каждое ядро будет выполнять одну и ту же последовательность операций, но над разными порциями данных. В задачах подобного рода используются свои наборы инструментов. Например, MPI (совокупность однопоточных процессов, возможно, работающих на разных узлах), OpenMP (как расширения языка программирования и соответствующая поддержка со стороны компилятора), Threading Building Blocks, HPX и т.п.

2. Concurrent computing. Т.е. использование всех доступных ядер для параллельного выполнения различных (почти) независимых задач. При этом, вероятно, каждая задача будет выполнять свой собственный набор операций. Тут используется несколько другой набор инструментов (хотя тот же Threading Building Blocks может пригодиться и здесь).

Соответственно, для того, чтобы давать советы, нужно понимать, что именно вы понимаете под "распараллеливанием обработки данных". Может статься (причем это наверняка так), что для ваших задач уже давным давно придуманы инструменты, которыми нужно просто суметь воспользоваться. А не пытаться повторить их на коленке с помощью WinAPI или низкоуровневых оберток над системным API (вроде std::mutex-а).
Re[3]: Вопрос по многопоточности для C++ проекта
От: chaotic-kotik  
Дата: 05.07.16 12:46
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

B>Зависит от задачи. Если время, которое будет затрачено на разделяемую задачу, сравнительно небольшое, то обращаться каждый раз к ядру, например, может быть слишком расточительно.


Нет, не зависит от задачи. Можно захватывать мьютекс относительно редко и ненадолго, но при этом система будет медленной (из-за cache line ping-pong-а и false sharing-а), а можно захватывать мютексы очень часто, на каждый чих вообще, но система будет работать быстро. Это вопрос дизайна алгоритмов и все. Никакая навороченная реализация примитивов синхронизации не спасет от их тупого использования.
Re[4]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 12:52
Оценка:
CK>а можно захватывать мютексы очень часто, на каждый чих вообще, но система будет работать быстро
Если система будет на каждый чих обращаться к ядру и засыпать в ожидании пробуждения, то о каком быстродействии может идти речь?
Re[5]: Вопрос по многопоточности для C++ проекта
От: chaotic-kotik  
Дата: 05.07.16 13:49
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

B>Если система будет на каждый чих обращаться к ядру и засыпать в ожидании пробуждения, то о каком быстродействии может идти речь?


А мьютексы на каждый чих обращаются к ядру? Если захватывается свободный мьютекс, никакого обращения к ядру не происходит. Системный вызов выполняется только тогда, когда поток нужно усыпить, ну а задача параллельного алгоритма — сделать так, чтобы поток практически никогда не нужно было усыплять.

Пример — у тебя есть некий реестр объектов и есть потоки, которые работают с объектами из этого реестра. Обычно каждый поток работает со своим уникальным набором объектов, поэтому ты создаешь по одному локальному реестру объектов на каждый поток. Когда поток хочет начать работать с неким объектом, он берет и переносит атомарно объект из глобального реестра в свой локальный, по прошествии таймаута объект возвращается обратно, ну то есть это по сути реализация lease схемы, много где такое используется.
У глобального реестра есть мьютекс, у локального реестра есть мьютекс, у самого объекта тоже может быть мьютекс. Если потоку нужно обратиться к объекту, который был уже захвачен другим потоком — он получает адрес локального реестра того потока, захватывает его мьютекс и обращается к объекту. Но fast path — это захват одного или двух uncontended мьютексов, локальных для потока, никаких обращений к ядру, никаких дорогих операций. Дорогие операции появляются в slow path — захват мьютекса, принадлежащего другому потоку, который использовался другим потоком и даже может быть в данный момент захвачен этим другим потоком. Но это редкая операция.

Вот такие алгоритмы я имел ввиду. Это многопоточное программирвоание, все что не учитывает разницу между contended и uncontended состояниями мьютексов и памяти — многопоточным программированием не является, это просто разнообразные thread-safe реализации, которые могут иногда даже работать быстрее на многоядерных и многопроцессорных машинах (а могут и медленнее. Рассуждения о синхронизации без вот этого вот контекста — просто пустая трата времени, которая показывает только то, что рассуждающий очень поверхностно понимает многопоточность.
Re[6]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 14:20
Оценка:
CK>А мьютексы на каждый чих обращаются к ядру?
Насколько я знаю, в Windows -- да.
Re[7]: Вопрос по многопоточности для C++ проекта
От: chaotic-kotik  
Дата: 05.07.16 15:51
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

CK>>А мьютексы на каждый чих обращаются к ядру?

B>Насколько я знаю, в Windows -- да.

Win API функции тоже могут делать что-нибудь в user-space. Я не знаю как это точно реализовано в win-api (не писал ничего под эту платформу лет эдак шесть), но например в linux никто никогда не делает системные вызовы напрямую — все вызовы завернуты в вызовы glibc и тот же pthread_mutex_lock много чего делает в userspace прежде чем делать системный вызов, там в принципе может и без системного вызова обойтись. Подозреваю в win32 api что-то похожее, ну либо у них там мьютекс это действительно голый объект ядра, а поддержку в userspace имеют только критические секции.
Re[8]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 16:02
Оценка:
CK>ну либо у них там мьютекс это действительно голый объект ядра, а поддержку в userspace имеют только критические секции.
Да.

Помимо этого, в Windows они могут шариться между процессами.
Re[2]: Вопрос по многопоточности для C++ проекта
От: AlexGin Беларусь  
Дата: 05.07.16 16:23
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, AlexGin, Вы писали:


AG>>Собираюсь делать новый проект на C++, при этом планирую активно

AG>>применять распарраллеливание обработки данных за счёт многопоточности.

S>Многопоточность -- это инструмент, который используется в двух сильно разных направлениях:


S>1. Parallel computing. Т.е. использование распараллеливания вычислений на все доступные ядра для уменьшения общего времени решения задачи. При этом, вероятно, каждое ядро будет выполнять одну и ту же последовательность операций, но над разными порциями данных. В задачах подобного рода используются свои наборы инструментов. Например, MPI (совокупность однопоточных процессов, возможно, работающих на разных узлах), OpenMP (как расширения языка программирования и соответствующая поддержка со стороны компилятора), Threading Building Blocks, HPX и т.п.

Да — именно об этом и идет речь в моём посте.

S>2. Concurrent computing. Т.е. использование всех доступных ядер для параллельного выполнения различных (почти) независимых задач. При этом, вероятно, каждая задача будет выполнять свой собственный набор операций. Тут используется несколько другой набор инструментов (хотя тот же Threading Building Blocks может пригодиться и здесь).

Это не для данного случая.

S>Соответственно, для того, чтобы давать советы, нужно понимать, что именно вы понимаете под "распараллеливанием обработки данных". Может статься (причем это наверняка так), что для ваших задач уже давным давно придуманы инструменты, которыми нужно просто суметь воспользоваться.

Вполне возможно.

S>А не пытаться повторить их на коленке с помощью WinAPI или низкоуровневых оберток над системным API (вроде std::mutex-а).

Дело в том, что в предшествующих разработках у меня наблюдалась работа над "вариантом 2".
Re[9]: Вопрос по многопоточности для C++ проекта
От: AlexGin Беларусь  
Дата: 05.07.16 16:30
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

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

B>Да.

B>Помимо этого, в Windows они могут шариться между процессами.


Нет — критические секции в WinAPI не разделяются между процессами:
https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms682608(v=vs.85).aspx

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of typeCRITICAL_SECTION. Before using a critical section, some thread of the process must call InitializeCriticalSection orInitializeCriticalSectionAndSpinCount to initialize the object.


Вот полезная инфа:
http://stackoverflow.com/questions/800383/what-is-the-difference-between-mutex-and-critical-section

Критические секции в WinAPI — это легковесные объекты, которые не являются объектами ядра (при их создании нет опции LPSECURITY_ATTRIBUTES).

Именно поэтому у меня и возник данный вопрос:
можно ли в Qt, boost, STL использовать такие штуковины, как критические секции, не влезая в WinAPI?

То, что мьютексы работают более медленно, чем крит-секции — это известно:
http://stackoverflow.com/questions/9997473/stdmutex-performance-compared-to-win32-critical-section
Отредактировано 05.07.2016 17:43 AlexGin . Предыдущая версия . Еще …
Отредактировано 05.07.2016 16:44 AlexGin . Предыдущая версия .
Отредактировано 05.07.2016 16:39 AlexGin . Предыдущая версия .
Отредактировано 05.07.2016 16:37 AlexGin . Предыдущая версия .
Re[3]: Вопрос по многопоточности для C++ проекта
От: so5team https://stiffstream.com
Дата: 05.07.16 16:53
Оценка:
Здравствуйте, AlexGin, Вы писали:

S>>Соответственно, для того, чтобы давать советы, нужно понимать, что именно вы понимаете под "распараллеливанием обработки данных". Может статься (причем это наверняка так), что для ваших задач уже давным давно придуманы инструменты, которыми нужно просто суметь воспользоваться.

AG>Вполне возможно.

Ну так приоткройте тайну, может вам более конкретные вещи посоветуют.
Re[4]: Вопрос по многопоточности для C++ проекта
От: AlexGin Беларусь  
Дата: 05.07.16 17:31
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, AlexGin, Вы писали:


S>>>Соответственно, для того, чтобы давать советы, нужно понимать, что именно вы понимаете под "распараллеливанием обработки данных". Может статься (причем это наверняка так), что для ваших задач уже давным давно придуманы инструменты, которыми нужно просто суметь воспользоваться.

AG>>Вполне возможно.

S>Ну так приоткройте тайну, может вам более конкретные вещи посоветуют.

Обработка данных. Эта обработка должна быть распараллелена по всем ядрам CPU.
Как подсчитать количество ядер — дело ясное:
    SYSTEM_INFO stInfo;
    GetSystemInfo(&stInfo);
    DWORD dwCPUCores = stInfo.dwNumberOfProcessors;

Ну а дальше — создать столько потоков (threads), сколько у нас ядер — и считать.
Все потоки считают по одинаковому алгоритму, складывают данные (результаты) в общие коллекции.
Вот собственно и все премудрости.
Re[5]: Вопрос по многопоточности для C++ проекта
От: so5team https://stiffstream.com
Дата: 05.07.16 18:02
Оценка: +1
Здравствуйте, AlexGin, Вы писали:

AG>Вот собственно и все премудрости.


Ну и чем вас не устраивает OpenMP?
Re[10]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 18:28
Оценка: :)
AG>Нет — критические секции в WinAPI не разделяются между процессами

Я про Mutex'ы.

AG>Именно поэтому у меня и возник данный вопрос:

AG>можно ли в Qt, boost, STL использовать такие штуковины, как критические секции

Да что вы так WinAPI боитесь-то? Напишите свой враппер, протестируйте его и забудьте про детали реализации.

Алсо, у Microsoft есть заголовочный файл concrt.h, в котором, помимо всего прочего, есть обёртка над критическими секциями. Насколько он публичный, я не в курсе, надо гуглить.
Re[5]: Вопрос по многопоточности для C++ проекта
От: b0r3d0m  
Дата: 05.07.16 18:31
Оценка:
AG>Как подсчитать количество ядер — дело ясное:
AG>
AG>    SYSTEM_INFO stInfo;
AG>    GetSystemInfo(&stInfo);
AG>    DWORD dwCPUCores = stInfo.dwNumberOfProcessors;
AG>


Зачем, когда в тех же std и boost уже давно есть абстракции в виде hardware_concurrency?
Re: Вопрос по многопоточности для C++ проекта
От: velkin Удмуртия https://kisa.biz
Дата: 05.07.16 18:59
Оценка: 18 (3)
Здравствуйте, AlexGin, Вы писали:

AG>В связи с этои возникает вопрос:

AG>Оптимальная (прежде всего с точки зрения производительности) реализация многопоточности:
AG>1) При помощи функций WinAPI — вероятно, это самый производительный вариант, однако недостаток — нет кроссплатформенности;
AG>2) Средствами Qt — QThread кроссплатформенность есть, вопрос по производительности не очевиден, доп-бонус — отсутствие сложного кода, как в п.1;
AG>3) Средствами STL — std::thread (примерно та же картина как и во втором пункте).
AG>Дополнительная красота третьего пункта — если будет серверное приложение, без GUI, то не нужно "притягивать за уши" доплнительные библиотеки.

AG>Какие могут быть соображения по выбору?


На самом деле никакого выбора из этих трёх пунктов нет, нужно брать средства Qt. Теперь маленькое отступление по поводу комментария выше:
http://doc.qt.io/qt-4.8/qthread.html
http://doc.qt.io/qt-5/qthread.html

int QThread::idealThreadCount () [static]
Возвращает идеальное количество потоков, которое может быть запущено в системе. Она делает запрос количества процессорных ядер, как реальных, так и логических. Эта функция возвращает -1, если количество процессорных ядер не может быть определено.


Ещё добавлю, что параллельное программирование в Qt состоит не из одного QThread.

http://doc.qt.io/qt-5/threads-technologies.html
1) QThread: Low-Level API with Optional Event Loops
2) QThreadPool and QRunnable: Reusing Threads
3) Qt Concurrent: Using a High-level API

Пояснение:
http://doc.crossplatform.ru/qt/4.8.x/html-qt/threads-qtconcurrent.html

Пространство имен QtConcurrent предоставляет высокоуровневые API, которые делают возможным написание многопоточных программ без использования низкоуровневых потоковых примитивов, таких как мьютексы, блокировки чтение-запись, условия ожидания или семафоры. Программы, написанные с помощью QtConcurrent, автоматически приводят количество используемых потоков в соответствие с доступным количеством процессорных ядер. Это означает, что приложения, написанные сегодня, будут продолжать масштабироваться при развертывании на многоядерных системах в будущем.


И немного классики:
http://www.intuit.ru/studies/courses/1156/190/lecture/4942?page=4

SISD (Single Instruction, Single Data) – системы, в которых существует одиночный поток команд и одиночный поток данных. К такому типу можно отнести обычные последовательные ЭВМ;
SIMD (Single Instruction, Multiple Data) – системы c одиночным потоком команд и множественным потоком данных. Подобный класс составляют многопроцессорные вычислительные системы, в которых в каждый момент времени может выполняться одна и та же команда для обработки нескольких информационных элементов; такой архитектурой обладают, например, многопроцессорные системы с единым устройством управления. Этот подход широко использовался в предшествующие годы (системы ILLIAC IV или CM-1 компании Thinking Machines), в последнее время его применение ограничено, в основном, созданием специализированных систем;
MISD (Multiple Instruction, Single Data) – системы, в которых существует множественный поток команд и одиночный поток данных. Относительно этого типа систем нет единого мнения: ряд специалистов считает, что примеров конкретных ЭВМ, соответствующих данному типу вычислительных систем, не существует и введение подобного класса предпринимается для полноты классификации; другие же относят к данному типу, например, систолические вычислительные системы (см. [51, 52]) или системы с конвейерной обработкой данных;
MIMD (Multiple Instruction, Multiple Data) – системы c множественным потоком команд и множественным потоком данных. К подобному классу относится большинство параллельных многопроцессорных вычислительных систем.


Причём за использование того же OpenMP, MPI или ещё чего-нибудь придётся заплатить свою цену. Если нужно обычное прикладное приложение, то проще использовать чистый Qt. Могу сказать и по другому, если используется Qt, то это явно прикладное приложение, а не какой-нибудь навороченный кластер на тысячи компьютеров, иначе это был бы boost или что-то в этом роде.

Таким образом логичнее всего делать проект на Qt, но изучить его возможности. Или взять для примера мой нетбук и десктоп:
http://ark.intel.com/ru/products/55637/Intel-Atom-Processor-N570-1M-Cache-1_66-GHz

Количество ядер 2
Количество потоков 4

http://ark.intel.com/ru/products/80807/Intel-Core-i7-4790K-Processor-8M-Cache-up-to-4_40-GHz

Количество ядер 4
Количество потоков 8

Разница между производительностью Intel® Atom™ Processor N570 и Intel® Core™ i7-4790K Processor просто огромна.
Intel Core i7-4790K @ 4.00GHz 11,197 попугаев
Intel Atom N570 @ 1.66GHz 576 попугаев

Но принципиальной разницы в программировании для того и другого процессора нет, просто нужно определиться с общей стратегией.
Отредактировано 05.07.2016 19:04 velkin . Предыдущая версия .
Re[3]: Вопрос по многопоточности для C++ проекта
От: kov_serg Россия  
Дата: 05.07.16 21:18
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

_>>Хочешь рапараленлить вычисления MPI, OpenACC, OpenCL


B>Тогда уж и про OpenMP не забываем.

Дык OpenMPI реализация MPI также как и MPICH
Re: Вопрос по многопоточности для C++ проекта
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 06.07.16 00:33
Оценка: 6 (2)
Здравствуйте, AlexGin, Вы писали:

AG>Актуален обмен данными между потоками.

Нужно сделать так чтобы был не актуален.
AG>Какие могут быть соображения по выбору?
QT
AG>Огромное спасибо, за любые мысли!
Только QT.
Sic luceat lux!
Re[7]: Вопрос по многопоточности для C++ проекта
От: PM  
Дата: 06.07.16 06:09
Оценка:
Здравствуйте, b0r3d0m, Вы писали:

CK>>А мьютексы на каждый чих обращаются к ядру?

B>Насколько я знаю, в Windows -- да.

Емнип, кажется у Рихтера давно читал, что при захвате CRITICAL_SECTION делается короткий спинлок чтобы сразу не уходить в ядро.

Вообще в Windows Vista кроме Aero темы появилось новое ядро с новыми примитивами: CONDITION_VARIABLE и SRWLOCK. Последний можно использовать в реализации std::mutex, но не знаю так ли это в Visual C++

https://msdn.microsoft.com/en-us/magazine/jj721588.aspx
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.