Многопоточность в .NET (Multithreading) Часть 1. Теория

GNOME - MONO

Многопоточность (aka Multithreading) есть в большинстве языков программирования.  В книгах на русском языке часто можно встретить термин "нить" по отношению к "потокам". Вообще "thread" переводится, как "нить", а не "поток", но термин поток больше соответствует семантике thread'ов. Я буду называть их потоками.

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

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

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

Теперь можно перейти непосредственно к работе с потоками в .NET на C#. Для работы с потоками нужно подключить в вашем классе пространство имён System.Threading. Основным нашим объектом является класс Thread (собственно "нить"). Поток ассоциируется с функцией, которую он будет выполнять в процессе работы. Выход из функции приводит к заверешнию потока.

Рассмотрим создание, запуск и прекращение работы потока.
Thread thread = new Thread(new ThreadStart(func));

В скобках указывается делегат хранящий указатель на функцию потока. Принимается два типа делегатов: для функций принимающий параметр, и для функций без параметра (ParametrizedThreadStart и ThreadStart, соответственно). О делегатах я возможно напишу позже.

Далее:
thread.Start(); или thread.Start(obj); - зупаск с параметром или без.
thread.Abort(); - остановка потока. При этом в функции потока генерируется исключение ThreadAbortException и, если вы хотите узнать о преждевременном завершении работы потока, нужно его обработать. Если не обработаете ничего страшного не случится.
Suspend и Resume являются устревшими способами синхронизации.

Чтобы заблокировать обращения от потока в некоторому общему объекту в памяти можно воспользоваться оператором lock. При этом если один поток уже находится в блоке lock этого объекта, другой не сможет в него попасть и будет ждать разблокировки объекта.

вернуться назад