Что “вещи состоят в том, чтобы знать” при дайвинге в многопоточное программирование в C++

Я в настоящее время работаю над приложением беспроводных сетей в C++, и он прибывает в точку, куда я собираюсь хотеть мультираспараллелить части программного обеспечения при одном процессе, вместо того, чтобы иметь их всех в отдельных процессах. Теоретически, я понимаю многопоточность, но я должен все же погрузиться в практически.

Что каждый программист должен знать при написании многопоточного кода в C++?

53
задан jalf 22 January 2010 в 08:47
поделиться

21 ответ

Я бы сосредоточился на дизайне той вещь, как можно больше разделенных, поэтому у вас есть минимальное количество общего вещей в потоках. Если вы убедитесь, что у вас нет статики и других ресурсов, разделяемых среди потоков (кроме тех, которые вы будете обмениваться, если вы спроектировали это с процессами вместо потоков), вы были бы в порядке.

Следовательно, хотя да, вы должны иметь в виду понятия, такие как замки, семафоры и т. Д., Лучший способ решать это, чтобы попытаться избежать их.

24
ответ дан 7 November 2019 в 08:34
поделиться

Вы должны иметь понимание программирования основных систем, в частности:

  • синхронно против асинхронного ввода-вывода (блокировки против блокировки )
  • Механизмы синхронизации, такие как блокировка и конструкции Mutex
  • Управление резьбой на целевой платформе
1
ответ дан 7 November 2019 в 08:34
поделиться

Убедитесь, что явно знают, какие объекты передаются и как они переданы.

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

играет адвокат дьявола с вашим кодом. Посмотрите на какой-нибудь код и подумайте, как я мог сломать это с помощью некоторого промежуточного промежутка поток. В какой-то момент этот случай произойдет.

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

2
ответ дан 7 November 2019 в 08:34
поделиться

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

Мне не пришлось писать много сильно-резьбового кода в C ++, но, как правило, узор потребительского производителя может быть очень полезен для эффективного использования нескольких потоков, избегая условий гонок, связанных с одновременным доступом.

Если вы можете использовать еще один из уже отлаженный код для обработки взаимодействия потока, вы в хорошей форме. Как новичок, есть искушение делать вещи в специальной моде - использовать «волатильную» переменную для синхронизации между двумя кусками кода. Избегайте этого как можно больше. Очень трудно написать код, который пуленепробиваемый в присутствии боковых потоков, поэтому найдите некоторый код, который вы можете доверять, и минимизировать использование примитивов низкого уровня как можно больше.

3
ответ дан 7 November 2019 в 08:34
поделиться

Мои лучшие советы для резьбы новичков:

  • Если вы, возможно, можете, использовать Параллелизм на основе задач , Intel TBB очевидный Это изолирует вас от шероховатых, хитрых деталей и более эффективно, чем все, что вы будете булыжничать. Основной недостаткой является эта модель не поддерживает все виды использования многопотативных; Он отлично подходит для эксплуатации MULTICORES для вычислительной мощности, менее хорошим, если вы хотели, чтобы потоки для ожидания блокировки ввода / вывода.

  • Узнайте, как прервать потоки (или в случае TBB, как сделать задачи завершены рано, когда вы решите, что вы не хотели результатов в конце концов). Новички, кажется, притягиваются к нитям, убивать функции, такие как мотыльки к пламени. Не делай этого ... Херб Саттер имеет большой короткую статью на этом.

3
ответ дан 7 November 2019 в 08:34
поделиться

В дополнение к другим упомянутым, вы должны узнать о асинхронных очередях сообщений. Они могут элегантно решать проблемы совместного использования данных и обработки событий. Этот подход работает хорошо, когда у вас есть одновременные государственные машины, которые должны общаться друг с другом.

Я не знаю о любом сообщении, проходящих в рамках, адаптированных для работы только на уровне потоков. Я видел только домашние решения. Пожалуйста, просьба, если вы знаете какие-либо существующие.

Редактировать:

Можно использовать очереди без блокировки из TBB Intel , либо как есть, либо в качестве основы для более общей очереди сообщений.

3
ответ дан 7 November 2019 в 08:34
поделиться

Убедитесь, что вы проверяете свой код в системе «Однократную систему CPU» и «Multi-CPU».

На основании комментариев: -

  • Одиночный розетки, одиночный сердечник
  • один разъем, два ядра
  • Один розетки, более двух ядер
  • Два розетка, одноъядерный каждая
  • два сокета, Сочетание одноразовых, двойных и многоядерных процессоров
  • Mulitple розетки, сочетание единичных, двойных и многоядерных процессоров

Ограничивающий фактор здесь будет стоить. В идеале, концентрируйтесь на типов системы, на котором будет работать ваш код.

6
ответ дан 7 November 2019 в 08:34
поделиться

Одна вещь, которую я нашел очень полезным, состоит в том, чтобы сделать приложение, настраиваемое в отношении фактического количества потоков, которые он использует для различных задач. Например, если у вас есть несколько потоков, доступа к базе данных, сделать количество этих потоков настраиваемым через параметр командной строки. Это чрезвычайно удобно при отладке - вы можете исключить проблемы с резьбой, установив число на 1 или заставить их, установив его на высокое число. Это также очень удобно при разработке, что является оптимальным количеством потоков.

7
ответ дан 7 November 2019 в 08:34
поделиться

Никогда не предполагайте, что внешние API ThreadSafe. Если он не указан в своих документах, не говорится , не вызывайте их одновременно из нескольких потоков. Вместо этого ограничите свое использование их в одну поток или используйте Mutex, чтобы предотвратить параллельные вызовы (это довольно похоже на вышеупомянутые библиотеки GUI).

Следующая точка связана с языком. Помните, что C ++ (в настоящее время) нет четко определенного подхода к потоке. Компилятор / оптимизатор не знают, можно ли назвать код одновременно. Ключевое слово ключевое слово полезно для предотвращения определенных оптимизаций (то есть кэширования полей памяти в регистров CPU) в многопоточных контекстах, но это NO Механизм синхронизации.

Я бы порекомендовал повысить примитивы синхронизации. Не связывайтесь с API на платформе. Они заставляют ваш код сложно портировать, потому что у них есть аналогичные функции на всех основных платформах, но немного разных деталей. Усиление решает эти проблемы, подвергая только общую функциональность для пользователя.

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

8
ответ дан 7 November 2019 в 08:34
поделиться

Вы должны прочитать о замках, Mutexes, Semaphores и переменных условиях.

Одно советское совет, если ваше приложение имеет какую-либо форму пользовательского интерфейса, убедитесь, что вы всегда измените его из потока UI. Большинство пользовательских интернет-кадров / каркасов UI (или ведут себя неожиданно), если вы получаете доступ к ним из фоновой нити. Обычно они обеспечивают некоторую форму диспетчеризации метода для выполнения некоторой функции в потоке пользовательского интерфейса.

10
ответ дан 7 November 2019 в 08:34
поделиться

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

Я читал книги по теме, но то, что я узнал, в нескольких пунктах:

  1. думать параллельно : представьте, что толпа проходит через код. Что происходит, когда метод называется, пока уже в действии?
  2. Подумайте общие : Представьте, что многие люди пытаются прочитать и изменять общие ресурсы одновременно.
  3. Дизайн : Избегайте проблем, которые могут поднять точки 1 и 2.
  4. Никогда не думайте, что вы можете игнорировать кромки, они укусит вас усердно.

Поскольку вы не можете определить тестирование одновременных конструкций (потому что промежуточное измерение выполнения резьбы не воспроизводимо), вы должны убедиться, что ваш дизайн надежный, аккуратно анализируя данные кода и документирование Как предполагается код быть использованным.

После того, как вы понимаете, как и где вы должны иметь узкое место вашего кода, вы можете прочитать документацию на инструментах, используемых для этого задания:

  1. Mutex (эксклюзивный доступ к ресурсу)
  2. Scoped Locks (хороший шаблон для блокировки / Разблокируйте Mutex)
  3. Семафоры (передача информации между потоками)
  4. ReadWrite Mutex (многие читатели, эксклюзивный доступ в записи)
  5. сигналы (как «убить» нить или отправить его сигнал прерывания, как поймать сигнал прерывания, как поймать Эти)
  6. Партия параллельного дизайна: босс / работник, производитель / потребитель и т. Д. (см. Schmidt )
  7. Специфические инструменты платформы: OpenMP, C Blocks, и т. Д.

Удачи! Параллельность это весело, просто возьми свое время ...

14
ответ дан 7 November 2019 в 08:34
поделиться

Я не являюсь экспертом вообще в этой теме. Просто некоторое правило большого пальца:

1) Дизайн для простоты , ошибки действительно трудно найти в одновременном коде даже в самых простых примерах.
2) C ++ предлагает вам очень элегантную парадигму для управления ресурсами (Mutex, Semaphore, ...): Raii . Я заметил, что намного проще работать с Boost :: Thread , чем работать с POSIX нити.
3) Создайте свой код как Безопасным потоком . Если вы этого не сделаете, ваша программа может ведать себя странно .

20
ответ дан 7 November 2019 в 08:34
поделиться

Код

<?php
    $foo = '<img class="foo bar test" title="test image" src="http://example.com/img/image.jpg" alt="test image" width="100" height="100" />';
    $array = array();
    preg_match( '/src="([^"]*)"/i', $foo, $array ) ;
    print_r( $array[1] ) ;

Вывод

http://example.com/img/image.jpg
-121--1268189-

Вы также пытались удалить его из первой модели? Я полагаю, что Rails автоматически загрузит любые файлы, которые у вас есть в каталоге lib , без необходимости требовать их явно.

-121--1428305-

Убедитесь, что вы знаете, что означает volatile и что он использует (что может быть не очевидно вначале).

Кроме того, при разработке многопоточного кода можно предположить, что неограниченное количество процессоров одновременно выполняет каждую строку кода в приложении. (er, каждая отдельная строка кода, которая возможна в соответствии с вашей логикой в коде.) И что все, что не помечено как изменчивое компилятор делает специальную оптимизацию для того, чтобы только поток, который изменил его, мог прочитать/установить его истинное значение, и все остальные потоки становятся мусором.

-2
ответ дан 7 November 2019 в 08:34
поделиться

Прежде чем давать какие-либо советы по программированию по нескольким потокам в C ++, я хотел бы задать вопрос, есть ли какая-либо особая причина, по которой вы хотите начать писать приложение в C ++?

Есть другие парадигмы программирования, где Вы используете многоъядерные ядра, не попадаете в многопоточное программирование. Одна такая парадигма - это функциональное программирование. Напишите каждую часть вашего кода как функции без побочных эффектов. Тогда легко запустить в нескольких потоках, не беспокоясь о синхронизации.

Я использую Erlang для своей цели развития. Он увеличился на производительность как минимум на 50%. Код работает не так быстро, как код, написанный в C ++. Но я заметил, что для большинства в автономном режиме обработки данных скорость не так важна, как распределение работы и максимально использовать аппаратное обеспечение. Erlang предоставляет простую модель параллелизма, где вы можете выполнить одну функцию в нескольких потоках, не беспокоясь о проблеме синхронизации. Написание нескольких резьбовых кодов легко, но отладки, которое требует времени. Я сделал многопоточное программирование в C ++, но в настоящее время я доволен моделью параллелизма Erlang. Стоит посмотреть.

0
ответ дан 7 November 2019 в 08:34
поделиться

Лучшая точность, по-видимому, составляет 9 метров. Общие ценности (открытый, хороший охват) составляет 17 м, 23 м и 49 метров. С деревьями, покрывающими небо, вы, вероятно, останусь под сто метров, но вряд ли достаточно точны для ГИС или что-то подобное.

-121--3665318-

Часть моего аспирантура в области исследований относится к параллелизму.

Я прочитал эту книгу и обнаружил, что это хорошее резюме подходов на уровне дизайна.

На основном техническом уровне у вас есть 2 основных варианта: потоки или сообщение. Резьбовые приложения являются самыми легкими, чтобы выйти из земли, поскольку Pthreads, Windows Threads или Boost Threads готовы к работе. Тем не менее, это приносит с собой сложность общей памяти.

Удобство для передачи сообщений, по-видимому, в основном ограничивается в этот момент на API MPI. Он устанавливает среду, в которой вы можете запустить задания и разделить вашу программу между процессорами. Это больше для суперкомпьютерных / кластеров, где нет внутренней общей памяти. Вы можете добиться аналогичных результатов с розетками и так далее.

На другом уровне вы можете использовать язык языка Pragmas: популярный сегодня - OpenMP. Я не использовал его, но, по-видимому, создает потоки через предварительную обработку или библиотеку ссылок.

Классическая проблема здесь синхронизация; Все проблемы в многопрограмме приходят из недетерминированной природы многопрограмм, которые могут избегать .

См. Методы временных данных Lamport для дальнейшего обсуждения синхронизации и времени.

Многопоточность не является чем-то, что может сделать только Ph.d.s и гуру, но вам придется быть довольно приличным, чтобы сделать это, не делая безумных жуков.

0
ответ дан 7 November 2019 в 08:34
поделиться

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

1
ответ дан 7 November 2019 в 08:34
поделиться

Оставайтесь вдали от MFC и его библиотека обмена сообщениями.
На самом деле, если вы видите, как MFC и потоки, приходящие к вам - запустите для холмов (*)

(*), если, конечно, если MFC исходит с холмов - в этом случае убегают от холмов.

2
ответ дан 7 November 2019 в 08:34
поделиться

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

Во-вторых, вы хотите иметь возможность работать на высоком уровне, сколько сможете. Не работайте на уровне блокировков и мьютексов, если вы сможете использовать существующую очередь Master-Work. Intel TBB выглядит многообещающим, немного более высоким уровнем, чем чистые потоки.

Третье, многопоточное программирование сложно. Уменьшите область вашего кода, где вы должны подумать об этом как можно больше. Если вы можете написать такое класс, что объекты этого класса всегда работают только в одном потоке, и нет статических данных, он значительно снижает то, что вам нужно беспокоиться в классе.

3
ответ дан 7 November 2019 в 08:34
поделиться

Держите вещи мертвыми максимально простыми. Лучше иметь более простую конструкцию (обслуживание, меньшие ошибки), чем более сложное решение, которое может иметь немного лучшего использования ЦП.

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

Избегайте ложных обмен на все расходы (Google этот термин).

Используйте пул резьбы, поэтому вы не часто создаете / уничтожающие потоки (это дорого и медленно).

Рассмотрим возможность использования OpenMP, Intel и Microsoft (возможно, другие) поддерживают это расширение C ++.

Если вы делаете Crunching номер, рассмотрите возможность использования Intel IPP, который внутренне использует оптимизированные функции SIMD (это не очень многопоточь, но является параллелизмом связанных сортов).

имеют тонны веселья.

2
ответ дан 7 November 2019 в 08:34
поделиться

Орм, отличный вопрос. Я думаю, что все серьезные программисты должны узнать о потоках, потому что в конечном итоге вы будет по крайней мере рассмотреть возможность их использования и вы действительно хотите быть готовы, когда это произойдет. Ошибки параллелизма могут быть невероятно тонкими, и лучший способ избежать их - знать, какие идиомы безопасны (-ish).

Я настоятельно рекомендую Вам прочитать книгу Параллельное программирование на Java: Принципы проектирования и узоры Дага Леа: http://gee.cs.oswego.edu/dl/cpj/

Леа тратит время не только на обучение вас концепциям, но и на то, чтобы показать правильные и неправильные способы использования примитивов параллельного программирования (в Java, но и для любой другой среды, которая использует параллельное использование стиля блокировки/сигнализации совместно используемой памяти). Больше всего он учит уважению сложности параллельного программирования.

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

-121--2754202-

Смотрите мой ответ здесь для надежной асинхронной функции request (): Как включить файл JavaScript в другой файл JavaScript?

-121--4951512-

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

В многопоточном программировании, с другой стороны, поведение программы является недетерминированным, потому что точная комбинация синхронизации того, какие потоки выполняются, для каких периодов времени (относительно друг друга) будет отличаться при каждом запуске программы. Так что просто запустить многопоточную программу несколько раз (или даже несколько миллионов раз) и сказать «она не рухнула для меня, поставь!» совершенно неадекватно.

Вместо этого, выполняя многопоточную программу, вы всегда должны пытаться доказать (по крайней мере, к собственному удовлетворению), что программа работает не только, но и что не может работать . Это намного труднее, потому что вместо проверки одного кодового пути вы фактически пытаетесь проверить почти бесконечное количество возможных кодовых путей.

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

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

Нити сильны juju. Используйте их скудно.

2
ответ дан 7 November 2019 в 08:34
поделиться

Я в той же лодке, что и вы, я только впервые начинаю многопоточность в рамках проекта и внимательно оглядываюсь сеть для ресурсов. Я нашел этот блог очень информативным. Часть 1 - это pthreads, но я связался, начиная с раздела ускорения.

0
ответ дан 7 November 2019 в 08:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: