Однопоточное выполнение

Эта статья находится на начальном уровне проработки, в одной из её версий выборочно используется текст из источника, распространяемого под свободной лицензией
Материал из энциклопедии Руниверсалис
Однопоточное выполнение
Single Threaded Execution
Описан в Design Patterns Нет

Однопоточное выполнение (англ. Single Threaded Execution или англ. Critical Section[1]) — параллельный шаблон проектирования, препятствующий конкурентному вызову метода, тем самым запрещая параллельное выполнение этого метода.

Мотивы

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

Следствия

  • + Обеспечивается безопасность потоков
  • − Производительность может быть снижена
  • − Возможна взаимная блокировка

Пример реализации

Пример 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 с. — ISBN 0471258393. (см. синопсис  (англ.))