Однопоточное выполнение
Однопоточное выполнение | |
---|---|
Single Threaded Execution | |
Описан в Design Patterns | Нет |
Однопоточное выполнение (англ. Single Threaded Execution или англ. Critical Sectionen:Critical section) — параллельный шаблон проектирования, препятствующий конкурентному вызову метода, тем самым запрещая параллельное выполнение этого метода.
Мотивы
- Класс содержит методы, которые обновляют или задают значения в переменных экземпляра класса или переменных класса.
- Метод манипулирует внешними ресурсами, которые поддерживают только одну операцию в какой-то момент времени.
- Методы класса могут вызываться параллельно различными потоками.
- Не существует временного ограничения, которое требовало бы от метода немедленного выполнения, как только его вызывают.
Следствия
- + Обеспечивается безопасность потоков
- − Производительность может быть снижена
- − Возможна взаимная блокировка
Пример реализации
Пример C#
using System;
using System.Threading;
namespace Digital_Patterns.Concurrency.Single_Thread_Execution
{
/// <summary>
/// Экземпляры класса <see cref="TrafficSensor"/> связаны с сенсором движения
/// транспорта, который фиксирует прохождение машиной некоторого места на
/// полосе движения.
/// </summary>
class TrafficSensor
{
private static Int32 mID = 0;
private ITrafficObserver _observer;
public Boolean IsRun { get; set; }
private Int32 _id;
/// <summary>
/// Конструктор
/// </summary>
/// <param name="observer">Объект, предназначенный для оповещения о том, что сенсор
/// движения транспорта, связанный с этим объектом,
/// обнаруживает проходящую машину.</param>
public TrafficSensor(ITrafficObserver observer)
{
_id = ++mID;
_observer = observer;
IsRun = true;
new Thread(Run).Start();
}
/// <summary>
/// Общая логика для потока этого объекта
/// </summary>
private void Run()
{
while (IsRun)
{
motitorSensor();
}
}
private static Random mRnd = new Random();
/// <summary>
/// Этом метод вызывает метод detect объекта, когда
/// связанный с ним сенсор движения транспорта фиксирует
/// проходящую машину
/// </summary>
private void motitorSensor()
{
//TODO Something
Thread.Sleep(mRnd.Next(1000));
var msg = System.Reflection.MethodInfo.GetCurrentMethod().Name;
Console.WriteLine(String.Format(@"{0} {1} +1", _id, msg));
detect();
}
/// <summary>
/// Этот метод вызывается методом <see cref="motitorSensor"/>,
/// чтобы сообщить о прохождении транспортного средства
/// наблюдателю этого объекта
/// </summary>
private void detect()
{
_observer.vehiclePassed();
}
/// <summary>
/// Классы должны реализовывать этот интерфейс,
/// чтобы объект <see cref="TrafficSensor"/> мог сообщить им о прохождении
/// машин
/// </summary>
public interface ITrafficObserver
{
/// <summary>
/// Вызывается тогда, когда <see cref="TrafficSensor"/> фиксирует
/// проходящее транспортное средство.
/// </summary>
void vehiclePassed();
}
}
}
using System;
namespace Digital_Patterns.Concurrency.Single_Thread_Execution
{
/// <summary>
/// Экземпляры класса <see cref="TrafficSensorController"/> хранят текущее
/// общее количество машин, прошедших мимо сенсоров движения транспорта,
/// связанных с экземпляром.
/// </summary>
class TrafficSensorController : TrafficSensor.ITrafficObserver
{
private Int32 _vehicleCount = 0;
/// <summary>
/// Этот метод вызывается в том случае, когда сенсор движения
/// транспорта фиксирует прохождение машины. Он увеличивает
/// значение счетчика машин на единицу.
/// </summary>
public void vehiclePassed()
{
lock (this)
{
++_vehicleCount;
}
}
/// <summary>
/// Сбрасывает счетчик машин в нуль
/// </summary>
/// <returns></returns>
public Int32 GetAndClearCount()
{
lock (this)
{
Int32 count = _vehicleCount;
_vehicleCount = 0;
return count;
}
}
}
}
using System;
using System.Threading;
namespace Digital_Patterns.Concurrency.Single_Thread_Execution
{
/// <summary>
/// Экземпляры класса <see cref="TrafficTransmitter"/> отвечают за передачу
/// занчения, определяющего количество машин, проходящих через данное место
/// дороги за одну минуту.
/// </summary>
class TrafficTransmitter
{
private TrafficSensorController _conrtoller;
private Thread _myThread;
public Boolean IsRun { get; set; }
/// <summary>
/// Конструктор
/// </summary>
/// <param name="conrtoller">От <see cref="TrafficSensorController"/> этот объект
/// будет получать значение счетчика количества прошедших
/// машин</param>
public TrafficTransmitter(TrafficSensorController conrtoller)
{
_conrtoller = conrtoller;
_myThread = new Thread(Run);
IsRun = true;
_myThread.Start();
}
/// <summary>
/// Передает значение счетчика количества машин, прошедших
/// за промежуток времени
/// </summary>
private void Run()
{
while (IsRun)
{
Thread.Sleep(10000);
Transmit(_conrtoller.GetAndClearCount());
}
}
private void Transmit(Int32 count)
{
//TODO Something
var msg = System.Reflection.MethodInfo.GetCurrentMethod().Name;
Console.WriteLine(String.Format(@"{0} {1}", msg, count));
}
}
}
using System;
using Digital_Patterns.Concurrency.Single_Thread_Execution;
namespace Digital_Patterns
{
class Program
{
static void Main(string[] args)
{
var controller = new TrafficSensorController();
var transmitter = new TrafficTransmitter(controller);
Console.WriteLine(@"Press any key for start, and press again for finish");
Console.ReadKey();
var sensor1 = new TrafficSensor(controller);
var sensor2 = new TrafficSensor(controller);
Console.ReadKey();
sensor1.IsRun = false;
sensor2.IsRun = false;
transmitter.IsRun = false;
Console.WriteLine();
}
}
}
Ссылки
- Mark Grand. Patterns in Java Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML (англ.). — Wiley & Sons, 1998. — 480 p. — ISBN 0471258393. (см. синопсис (англ.))