Как правило, вам нужен механизм блокировки (критические секции являются механизмом блокировки) всякий раз, когда несколько потоков могут получить доступ к общему ресурсу одновременно, и по крайней мере один из потоков будет записывать / изменять общий ресурс.
Это верно, является ли ресурс объектом в памяти или файлом на диске.
И причина, по которой необходима блокировка, заключается в том, что если операция чтения происходит одновременно с операцией записи, операция чтениявероятность получения противоречивых данных, приводящих к непредсказуемому поведению.
Стивен Чеунг упомянул конкретные аспекты платформы в отношении обработки файлов, и я не буду их здесь повторять.
В качестве примечания яХотелось бы подчеркнуть еще одну проблему параллелизма, которая может быть применима в вашем случае.
- Предположим, один поток читает некоторые данные и начинает обработку.
- Затем другой поток делает то же самое.
- Оба потока определяют, что они должны записать результат впозиция X файла A.
- В лучшем случае записываемые значения одинаковы, и один из потоков фактически ничего не делал, кроме как тратит время.
- В худшем случае вычисление одного изпотоки перезаписываются, а результат теряется.
Вам необходимо определить, будет ли это проблемой для вашего приложения.И я должен указать, что, если это так, простое блокирование операций чтения и записи не решит проблему.Кроме того, попытка увеличить продолжительность блокировок приводит к другим проблемам.
Опции
Критические секции
Да, вы можете использовать критические секции.
- Вам нужно будет выбрать лучшую гранулярность критических разделов: по одному на весь файл или, возможно, использовать их для обозначения определенных блоков в файле.
- Решение потребует лучшего пониманиячто делает ваше приложение, поэтому я не собираюсь отвечать за вас.
- Просто помните о возможности взаимоблокировок:
- Поток 1 получает блокировку A
- Поток 2получает блокировку B
- поток 1 желает блокировки B, но должен ждать
- поток 2 желает блокировки A - вызывая взаимоблокировку, поскольку ни один из потоков не может снять полученную блокировку.
Я также собираюсь предложить 2 других инструмента, которые вы должны рассмотреть в своем решении.
Однопоточный
Какая шокирующая вещь!А если серьезно, если вы решили использовать многопоточность как «сделать приложение быстрее», то вы пошли по многопоточности по причине неправильно .Большинство людей, которые делают это, в действительности делают свои приложения, более трудными для написания, менее надежными и медленнее !
Это слишком распространенное заблуждение, что множественноепотоки ускоряют приложения.Если для выполнения задачи требуется X тактов - потребуется X тактов!Несколько потоков не ускоряют выполнение задач, это позволяет выполнять несколько задач параллельно.Но это может быть плохо !...
Вы описали, что ваше приложение сильно зависит от чтения с диска, анализа того, что читается, и записи на диск.В зависимости от того, насколько интенсивным является процесс анализа, вы можете обнаружить, что все ваши потоки тратят большую часть своего времени на ожидание операций дискового ввода-вывода.В этом случае множественные потоки обычно служат только для того, чтобы переместить головки дисков в дальние «углы» ваших (ummm round ) дисковых пластин.Дисковый ввод-вывод по-прежнему является узким местом, и потоки заставляют его вести себя так, как будто файлы максимально фрагментированы.
Операции с очередями
Предположим, что ваша причина перехода к многопоточности верна, иу вас все еще есть потоки, работающие на общих ресурсах.Вместо использования блокировок во избежание проблем с параллелизмом, вы могли бы ставить свои операции с общими ресурсами в определенные потоки.
Таким образом, вместо потока 1:
- Чтение позиции X из файла A
- Анализ данных
- Запись в позицию Y в файле A
Создать другой поток;поток FileA:
- FileA имеет очередь инструкций
- Когда он добирается до инструкции для чтения позиции X, он делает это.
- Он отправляетданные в поток 1
- поток 1 анализирует свои данные --- в то время как поток FileA продолжает обрабатывать инструкции
- поток 1 помещает инструкцию для записи своего результата в позицию Y в конце очереди потока FileA -- пока поток FileA продолжает обрабатывать другие инструкции.
- В конце концов поток FileA запишет данные в соответствии с требованиями Trhead 1.