Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Синхронизованное свойство


Автор: DEER 20.6.2006, 10:34
господа. возникла пара вопросов, касающихся синхронизации методов в C#.
точнее мне надо синхронизировать свойство (get и set как я понимаю) некоего объекта.
поиском пользовался кое что нашел полезное. (http://forum.vingrad.ru/index.php?showtopic=41277&view=findpost&p=316625)
Осталось упочнить детали.
итак.
суть моёй задачки такова
Цитата
Реализуйте 'синхронное' cвойство SharedRes типа Employee. Класс Employee  определен следующим образом
class Employee
{
  string fname
  string lname
  int Age
}
То есть,  свойство, самостоятельно заботящиеся о том, чтобы одновременно обращающиеся к нему потоки работали с ним корректно.

Правила такого обращения следуюшие: 
1. Записывать в одно время может только один поток, любой следующий 'писатель' должен ждать(блокироваться). 
2. Если один поток выполняет запись, то любой читатель должен ждать завершения 
этой записи. 
3. Пока происходит чтение свойства запись невозможна. 
4. Однако требуется избежать такой ситуации , когда запись невозможна изза сменяющих друг друга операций чтения. 
5. Любое количнеств читающих потоков могут читать одновременно. 

я пишу класс, у которого будет поле empl, например.
Создаю для него свойство
Код

 public Employee SharedRes
{
   get
   { //тут надо окончания записи в поле, читать могут несколько,
   }
   set
   { //тут надо ждать окончания чтения,  и окончания записи.
   }
}

вроде всё ясно, кроме правила № 4.
Далее приступаем к реализации. Domestic Cat использовал в примере поле private bool isBeerReady;. Если такой подход корректный, то добавлю в мой класс поля
Код

private bool isReading; // идет чтение
private bool isWriting; // идет запись

и теперь можно реализовать само свойство.
Код

 public Employee SharedRes
{
   get
   { //тут надо окончания записи в поле, читать могут несколько,
      lock(this.empl)
      {
          while(isWriting)
          {
              Monitor.Wait(this.empl); //что за монитор??? не понятно
          }
          isReading = true;
          Thread.sleep(5); //типа задержка
          return this.empl; // отдаем объект
          isReading = false;
      }
   }
   set
   { //тут надо ждать окончания чтения,  и окончания записи.
      lock(this.empl)
      {
          while(isWriting || isReading)
          {
              Monitor.Wait(this.empl); //что за монитор??? не понятно
          }
          isWriting = true;
          Thread.sleep(5); //типа задержка
          this.empl = value; //записываем объект
          isWriting = false;
      }
   }
}


скажите, правильно ли я понял использование lock, что надо указывать какой объект захватываем.
что такое Monitor и правильно ли я его использую.
как можно реализовать 4-е правило из задания. Я просто не до конца его понял.

заранее сенкс  

Автор: ivashkanet 20.6.2006, 11:00
Пройдусь по коду  smile 
Цитата(DEER @  20.6.2006,  10:34 Найти цитируемый пост)
Thread.sleep(5); //типа задержка

Не должно быть у тебя задержки. Доместикс делал ее для емуляции процесса выпивания пива
Пока все. В остальном я пас   smile 
 

Автор: DEER 20.6.2006, 11:08
ivashkanet,  спасиба, но она должна быть по заданию, я просто не всё задание написал  smile  

Автор: mr.DUDA 20.6.2006, 11:41
DEER, насчёт того, почему внутри блока lock используется Monitor - тут непонятка: если доступ к empl заблокирован для доступа из более чем одного потока (пресловутый lock), то зачем когда уже вошли внутрь lock - ещё и ждать монитором ? Всё равно при использовании lock более чем один reader или writer не сможет в одно и то же время работать с empl.

З.Ы. описываемая задача уже реализована средствами Framework - это класс ReaderWriterLock.   

Автор: DEER 20.6.2006, 11:47
mr.DUDA,   smile  точно! те сначала надо писать проверу а потом уже лочить..
Код

 public Employee SharedRes    
{    
   get    
   { //тут надо окончания записи в поле, читать могут несколько,    
          while(isWriting)    
          {    
              Monitor.Wait(this.empl); //что за монитор??? не понятно    
          }    
      lock(this.empl)    
      {    
          isReading = true;    
          Thread.sleep(5); //типа задержка    
          return this.empl; // отдаем объект    
          isReading = false;    
      }    
   }    
   set    
   { //тут надо ждать окончания чтения,  и окончания записи.    
          while(isWriting || isReading)    
          {    
              Monitor.Wait(this.empl); //что за монитор??? не понятно    
          }    
      lock(this.empl)    
      {    
          isWriting = true;    
          Thread.sleep(5); //типа задержка    
          this.empl = value; //записываем объект    
          isWriting = false;    
      }    
   }    
}

вот так получается?  smile 
на счет того что она решена... я это предполагал, но решить надо самому.это типа тестовое задание 

Автор: mr.DUDA 20.6.2006, 16:20
А какой глубокий смысл делать ожидание, если вход в lock и так ожидает выхода из lock другого потока ?

З.Ы. оператор lock сам по себе реализован на основе Monitor-ов, между прочим smile 

Автор: DEER 20.6.2006, 16:52
ну вот я и спрашиваю. правильно я их использую или нет?

Добавлено @ 16:53 
тут посоветовали вообще без локов делать... 

Автор: Аленка 21.6.2006, 09:35
А как без локов получилось? Если получилось?

Код

while(isWriting || isReading)     
          {     
              Monitor.Wait(this.empl); //что за монитор??? не понятно     
          }     
      lock(this.empl)     
     

так не получится, lock()-это тоже самое что Monitor.Enter() +Monitor.Exit(). Т.е. надо сначала сделать enter, затем wait, exit.

 4 пункт- это классическая проблема writers-readers. Может решиться введением дополнительных переменных, считающих количество ожидающих writerов и readerов.
Проверка такая: если readerов больше нет, и есть writer, то запускаем его. Пока не закончатся smile


 

Автор: DEER 21.6.2006, 11:09
Цитата
А как без локов получилось? Если получилось?

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

Добавлено @ 11:12 
выгладит вот так
Код

    public class MyClass
    {
        CEmployee empl;
        public MyClass()
        {
            empl = new CEmployee();
            isReading = false;
            isWriting = false;
            isWriteWaiting = false;
        }
        private bool isReading;// true, если идёт чтение
        private bool isWriting;// true, если идет запись
        private bool isWriteWaiting;// true, если есть в очереди на запись

    //    [Synchronization]
        public CEmployee SharedRes
        {
            get
            {//тут надо ждать окончания записи, читать могут несколько но приоритет у записи
                try
                {
                    while(isWriting||isWriteWaiting)
                    { 
                        Monitor.Wait(this.empl, 5);//ждем пока освободится объект 
                    }
                    Monitor.Enter(this.empl);
                    isReading = true;
                    Thread.Sleep(10);
                    isReading = false;
                    Monitor.Exit(this.empl);
                    return empl;
                }
                catch(Exception ee)
                {
                    return empl;
                }
            }
            set
            {//тут надо ждать окончания чтения, и окончания записи
                try
                {
                    isWriteWaiting = true;
                    while(isWriting||isReading)
                    { 
                        Monitor.Wait(this.empl, 5);//ждем пока освободится объект 
                    }
                    Monitor.Enter(this.empl);
                    isWriteWaiting = false;
                    isWriting = true;
                    Thread.Sleep(10);
                    empl.Name = value.Name;
//                    Thread.Sleep(10);
                    empl.LastName = value.LastName;
//                    Thread.Sleep(10);
                    empl.Age = value.Age;
//                    Thread.Sleep(10);
                    isWriting = false;
                    isWriteWaiting = false;
                    Monitor.Exit(this.empl);
                }
                catch(Exception ee)
                {
                    //
                }            
            }
        }
    }

 

Автор: Аленка 21.6.2006, 11:30
А как тестируешь?

Код

WorkerClass w = new WorkerClass();
...
Thread workerThread = new Thread(new ThreadStart(w.DoSomeWork));


 что передаешь вместо DoSomeWork?  

Автор: DEER 21.6.2006, 16:41
тест не очень получился...
Код

        private MyClass m;
        public void Writer()
        {
            for(int i=0; i<50; i++)
            {
                listBox1.Items.Add("пишу данные");
                m.SharedRes = new CEmployee("Один"+i.ToString(), "Одинович"+i.ToString(), i);
            }
        }
        public void Reader()
        {
            for(int i =0; i<50; i++)
            {
                listBox1.Items.Add("читаю данные");
                CEmployee tmpEmpl = m.SharedRes;
                listBox1.Items.Add(tmpEmpl.Name+"-"+tmpEmpl.LastName+"-"+tmpEmpl.Age.ToString());
            }
        }
        private void button1_Click(object sender, System.EventArgs e)
        {
            m = new MyClass();
            //потоки писатели
            Thread tw1 = new Thread(new ThreadStart(Writer));
            Thread tw2 = new Thread(new ThreadStart(Writer));
            //потоки - читатели
            Thread tr1 = new Thread(new ThreadStart(Reader));
            Thread tr2 = new Thread(new ThreadStart(Reader));
            tw1.Start();
            tw2.Start();
            tr1.Start();
            tr2.Start();
        }
 

Автор: YoungMan 13.7.2006, 21:30
Если использовать код, приведенный DEER-ом, то получим, что "читатели" будут выводить "скомканные" данные о сотруднике:
Один1-Одинович1-1
Один2-Одинович1-1
Один2-Одинович2-1
Один2-Одинович2-1
Один2-Одинович2-2
Один3-Одинович2-2
Один3-Одинович3-2
Один3-Одинович3-3
...
(текст функции writer опущен)

Вопрос: как от этого избавиться? 

Автор: YoungMan 13.7.2006, 22:01
и еще вопрос, почему если убрать конструкцию try-catch появляются ошибки типа:
Код

An unhandled exception of type 'System.Threading.SynchronizationLockException' occurred in mscorlib.dll
Additional information: Object synchronization method was called from an unsynchronized block of code. 

в месте проверки условия циклов: 
Код

while(isWriting||isWriteWaiting)
и 
Код

while(isWriting||isReading)
 

Автор: YoungMan 14.7.2006, 05:57
На мой взгляд класс MyClass должен выглядеть вот так:
Код

public class MyClass
    {
        Employee empl;
        public MyClass()
        {
            empl = new Employee();
            isReading = false;
            isWriting = false;
            isWriteWaiting = false;
        }
        private bool isReading;// true, если идёт чтение
        private bool isWriting;// true, если идет запись
        private bool isWriteWaiting;// true, если есть в очереди на запись

        private static object somePrivateStaticObject = new Object();

        public Employee SharedRes
        {
            get
            {//тут надо ждать окончания записи, читать могут несколько но приоритет у записи
                    Employee tEmpl;
                    
                        do
                        { 
                            Monitor.TryEnter(this.empl, 10);
                            //ждем пока освободится объект 
                        }
                        while(isWriting||isWriteWaiting);
                        isReading = true;
                        tEmpl = this.empl;
                        Thread.Sleep(10);
                        isReading = false;
                        Monitor.Exit(this.empl);

                    return tEmpl;
            }
            set
            {//тут надо ждать окончания чтения, и окончания записи
                        isWriteWaiting = true;
                        do
                        { 
                            Monitor.TryEnter(this.empl, 10);
                            //ждем пока освободится объект 
                        }
                        while(isWriting||isReading);
                        isWriting = true;
                        isWriteWaiting = false;
                        Thread.Sleep(10);
                        empl.fname = value.fname;
                        Thread.Sleep(10);
                        empl.lname = value.lname;
                        Thread.Sleep(10);
                        empl.Age = value.Age;
                        Thread.Sleep(10);
                        isWriting = false;
                        Monitor.Exit(this.empl);
            }
        }
    }
 

Автор: Аленка 14.7.2006, 19:57
Цитата(YoungMan @ 13.7.2006,  22:01)
и еще вопрос, почему если убрать конструкцию try-catch появляются ошибки типа:
Код

An unhandled exception of type 'System.Threading.SynchronizationLockException' occurred in mscorlib.dll
Additional information: Object synchronization method was called from an unsynchronized block of code. 


Потому и появляются, что Object synchronization method was called from an unsynchronized block of code.
 try catch похоже просто позволяет избежать потенциальных ошибок при обращении к уже используемому монитору. Синхронизировать надо использование монитора.
И скомканные данные получаются, потому что нет синхронизации.   

Автор: YoungMan 15.7.2006, 19:41
Это я уже понял.
Решая данную задачу через ReaderWriterLock класс, у сеня получилось так:
    
Код

public class MyClass
    {        
        #region Конструктор
        /// <summary>
        /// Конструктор класса
        /// </summary>
        public MyClass()
        {
            oEmpl = new Employee();
            rnd = new Random();
            rwl = new ReaderWriterLock();
        }
        #endregion

        #region Поля класса
        /// <summary>
        /// Объект класса сотрудник
        /// </summary>
        private Employee oEmpl = null;
        /// <summary>
        /// Определяет блокировку с возможностью одновременного множественного чтения и одничной записи
        /// </summary>
        public static ReaderWriterLock rwl;
        /// <summary>
        /// Реализация случайной величины
        /// </summary>
        private Random rnd;
        #endregion

        #region Открытые свойства класса
        /// <summary>
        /// "Синхронизированное"  свойство чтения(записи) информации о сотруднике
        /// </summary>
        public Employee SharedRes
        {
            get
            {
                try
                {
                    rwl.AcquireReaderLock(1000);
                    try
                    {
                        Employee tEmpl;
                        tEmpl = this.oEmpl;
                        Thread.Sleep(rnd.Next(20));
                        return tEmpl;
                    }
                    finally
                    {
                        rwl.ReleaseReaderLock();
                    }
                }
                catch(Exception)
                {
                    return null;
                }

            }
            set
            {
                try
                {
                    rwl.AcquireWriterLock(1000);
                    try
                    {
                        this.oEmpl.fname = value.fname;
                        Thread.Sleep(rnd.Next(20));
                        this.oEmpl.lname = value.lname;
                        Thread.Sleep(rnd.Next(20));
                        this.oEmpl.Age = value.Age;
                        Thread.Sleep(rnd.Next(20));
                    }
                    finally
                    {
                        rwl.ReleaseWriterLock();
                    }
                }
                catch(Exception)
                {
                }

            }
        }

        #endregion
    }

Но у меня все равно иногда проскакивает "скомканный вывод", чего быть по идее не долно.
класс вызова:
Код

    public class ThreadApp : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button btnStrStp;
        private System.Windows.Forms.ListBox listBox;

        /// <summary>
        /// Флаг запуска(остановки) приложения
        /// </summary>
        private bool bStrStp;
        /// <summary>
        /// Переменная класса чтения/записи
        /// </summary>
        private MyClass m;
        /// <summary>
        /// Количиство "писателей"
        /// </summary>
        private static int iWriter;
        /// <summary>
        /// Количиство "читателей"
        /// </summary>
        private static int iReader;
        /// <summary>
        /// Общее количетво потоков
        /// </summary>
        int iNemberOfTreads = 12;        
        /// <summary>
        /// Массив потоков
        /// </summary>
        Thread[] tPool;

        static ReaderWriterLock rwl = new ReaderWriterLock();

        private System.ComponentModel.Container components = null;

        public ThreadApp()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            CustomInitialize();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.listBox = new System.Windows.Forms.ListBox();
            this.btnStrStp = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // listBox
            // 
            this.listBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
                | System.Windows.Forms.AnchorStyles.Left) 
                | System.Windows.Forms.AnchorStyles.Right)));
            this.listBox.Location = new System.Drawing.Point(8, 0);
            this.listBox.Name = "listBox";
            this.listBox.Size = new System.Drawing.Size(304, 329);
            this.listBox.TabIndex = 0;
            // 
            // btnStrStp
            // 
            this.btnStrStp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.btnStrStp.Location = new System.Drawing.Point(320, 8);
            this.btnStrStp.Name = "btnStrStp";
            this.btnStrStp.Size = new System.Drawing.Size(96, 24);
            this.btnStrStp.TabIndex = 1;
            this.btnStrStp.Text = "Пуск";
            this.btnStrStp.Click += new System.EventHandler(this.btnStrStp_Click);
            // 
            // ThreadApp
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(416, 334);
            this.Controls.Add(this.btnStrStp);
            this.Controls.Add(this.listBox);
            this.Name = "ThreadApp";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// Точка входа приложения
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new ThreadApp());
        }
        
        /// <summary>
        /// Обработка событий нажатия кнопки (Запуск/Остановка приложения)
        /// </summary>
        /// <param name="sender">Ресурс события</param>
        /// <param name="e">Информация о событии</param>
        private void btnStrStp_Click(object sender, System.EventArgs e)
        {
            //Изменение значения флага запуска(остановки)
            bStrStp = !bStrStp;

            // Запуск / остановка приложения
            if (!bStrStp)
            {
                for(int i=0; i<iNemberOfTreads; i++)
                {
                    tPool[i].Join();
                }                
                btnStrStp.Text = "Пуск";
            }
            else
            {
                Start();
                btnStrStp.Text = "Остановка";
            }
            
        }

        /// <summary>
        /// Определение пользовательских переменных
        /// </summary>
        private void CustomInitialize()
        {
            bStrStp = false;
            m = new MyClass();
            iWriter = 0;
            iReader = 0;
            tPool = new Thread[iNemberOfTreads];

        }
        /// <summary>
        /// Функция запуска приложения
        /// </summary>
        private void Start()
        {
            //Формирование потоков чтения/записи
            for(int i = 0; i<iNemberOfTreads; i++)
            {
                if (i%6 == 0)
                    //поток "писатель"
                    tPool[i] = new Thread(new ThreadStart(Write));
                else
                    //поток "читатель"
                    tPool[i] = new Thread(new ThreadStart(Read));
                tPool[i].Name = new String(Convert.ToChar(i + 65), 1);
                tPool[i].Start();
                Thread.Sleep(10);
            }
        }
        /// <summary>
        /// Функция записи данных о сотруднике
        /// </summary>
        private void Write()
        {
            int iWriterIndex = ++iWriter;
            int index = 0;
            while(bStrStp)
            {
                string sFName = "Имя_" + iWriterIndex.ToString() + "_" + (++index).ToString();
                string sLName = "Фамилия_"+ iWriterIndex.ToString() + "_" + index.ToString();
                int iAge = iWriterIndex*1000 + index;
                m.SharedRes = new Employee(sFName, sLName, iAge);
                listBox.Items.Add("Writer (" + iWriterIndex + "): Выполнен " + index.ToString());
            }
        }
        /// <summary>
        /// Функция чтения данных о сотруднике
        /// </summary>
        private void Read()
        {
            int iReaderIndex = ++iReader;
            int index = 0;
            while(bStrStp)
            {
                ++index;
                try
                {
                    rwl.AcquireReaderLock(1000);
                    try
                    {
                        Employee oEmpl = m.SharedRes;
                        if (!(oEmpl == null))
                            listBox.Items.Add("Reader (" + iReaderIndex + "|" + index.ToString() + "): " + oEmpl.fname + "*" + oEmpl.lname + "*" + oEmpl.Age.ToString());
                    }
                    finally
                    {
                        rwl.ReleaseReaderLock();            
                    }    
                }
                catch(Exception)
                {
                }
            }
        }

    }

Не подскажите что я не правильно делаю? 

Автор: YoungMan 15.7.2006, 19:48
сори, вот новый новый класс вызова:
Код

    public class ThreadApp : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button btnStrStp;
        private System.Windows.Forms.ListBox listBox;

        /// <summary>
        /// Флаг запуска(остановки) приложения
        /// </summary>
        private bool bStrStp;
        /// <summary>
        /// Переменная класса чтения/записи
        /// </summary>
        private MyClass m;
        /// <summary>
        /// Количиство "писателей"
        /// </summary>
        private static int iWriter;
        /// <summary>
        /// Количиство "читателей"
        /// </summary>
        private static int iReader;
        /// <summary>
        /// Общее количетво потоков
        /// </summary>
        int iNemberOfTreads = 12;        
        /// <summary>
        /// Массив потоков
        /// </summary>
        Thread[] tPool;

        private System.ComponentModel.Container components = null;

        public ThreadApp()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            CustomInitialize();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.listBox = new System.Windows.Forms.ListBox();
            this.btnStrStp = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // listBox
            // 
            this.listBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
                | System.Windows.Forms.AnchorStyles.Left) 
                | System.Windows.Forms.AnchorStyles.Right)));
            this.listBox.Location = new System.Drawing.Point(8, 0);
            this.listBox.Name = "listBox";
            this.listBox.Size = new System.Drawing.Size(304, 329);
            this.listBox.TabIndex = 0;
            // 
            // btnStrStp
            // 
            this.btnStrStp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this.btnStrStp.Location = new System.Drawing.Point(320, 8);
            this.btnStrStp.Name = "btnStrStp";
            this.btnStrStp.Size = new System.Drawing.Size(96, 24);
            this.btnStrStp.TabIndex = 1;
            this.btnStrStp.Text = "Пуск";
            this.btnStrStp.Click += new System.EventHandler(this.btnStrStp_Click);
            // 
            // ThreadApp
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(416, 334);
            this.Controls.Add(this.btnStrStp);
            this.Controls.Add(this.listBox);
            this.Name = "ThreadApp";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// Точка входа приложения
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new ThreadApp());
        }
        
        /// <summary>
        /// Обработка событий нажатия кнопки (Запуск/Остановка приложения)
        /// </summary>
        /// <param name="sender">Ресурс события</param>
        /// <param name="e">Информация о событии</param>
        private void btnStrStp_Click(object sender, System.EventArgs e)
        {
            //Изменение значения флага запуска(остановки)
            bStrStp = !bStrStp;

            // Запуск / остановка приложения
            if (!bStrStp)
            {
                for(int i=0; i<iNemberOfTreads; i++)
                {
                    tPool[i].Join();
                }                
                btnStrStp.Text = "Пуск";
            }
            else
            {
                Start();
                btnStrStp.Text = "Остановка";
            }
            
        }

        /// <summary>
        /// Определение пользовательских переменных
        /// </summary>
        private void CustomInitialize()
        {
            bStrStp = false;
            m = new MyClass();
            iWriter = 0;
            iReader = 0;
            tPool = new Thread[iNemberOfTreads];

        }
        /// <summary>
        /// Функция запуска приложения
        /// </summary>
        private void Start()
        {
            //Формирование потоков чтения/записи
            for(int i = 0; i<iNemberOfTreads; i++)
            {
                if (i%6 == 0)
                    //поток "писатель"
                    tPool[i] = new Thread(new ThreadStart(Write));
                else
                    //поток "читатель"
                    tPool[i] = new Thread(new ThreadStart(Read));
                tPool[i].Name = new String(Convert.ToChar(i + 65), 1);
                tPool[i].Start();
                Thread.Sleep(10);
            }
        }
        /// <summary>
        /// Функция записи данных о сотруднике
        /// </summary>
        private void Write()
        {
            int iWriterIndex = ++iWriter;
            int index = 0;
            while(bStrStp)
            {
                string sFName = "Имя_" + iWriterIndex.ToString() + "_" + (++index).ToString();
                string sLName = "Фамилия_"+ iWriterIndex.ToString() + "_" + index.ToString();
                int iAge = iWriterIndex*1000 + index;
                m.SharedRes = new Employee(sFName, sLName, iAge);
                listBox.Items.Add("Writer (" + iWriterIndex + "): Выполнен " + index.ToString());
            }
        }
        /// <summary>
        /// Функция чтения данных о сотруднике
        /// </summary>
        private void Read()
        {
            int iReaderIndex = ++iReader;
            int index = 0;
            while(bStrStp)
            {
                ++index;
                Employee oEmpl = m.SharedRes;
                if (!(oEmpl == null))
                    listBox.Items.Add("Reader (" + iReaderIndex + "|" + index.ToString() + "): " + oEmpl.fname + "*" + oEmpl.lname + "*" + oEmpl.Age.ToString());
            }
        }

    }


Но вопрос остается "скомканности" остается  smile  

Автор: YoungMan 15.7.2006, 20:28
 smile А в таком варианте все нормально:
Код

public class MyClass
    {        
        #region Конструктор
        /// <summary>
        /// Конструктор класса
        /// </summary>
        public MyClass()
        {
            oEmpl = new Employee();
            rnd = new Random();
            rwl = new ReaderWriterLock();
        }
        #endregion

        #region Поля класса
        /// <summary>
        /// Объект класса сотрудник
        /// </summary>
        private Employee oEmpl = null;
        /// <summary>
        /// Определяет блокировку с возможностью одновременного множественного чтения и одничной записи
        /// </summary>
        private static ReaderWriterLock rwl;
        /// <summary>
        /// Реализация случайной величины
        /// </summary>
        private Random rnd;
        #endregion

        #region Открытые свойства класса
        /// <summary>
        /// "Синхронизированное"  свойство чтения(записи) информации о сотруднике
        /// </summary>
        public Employee SharedRes
        {
            get
            {
                //чтенение данных о сотруднике
                try
                {
                    rwl.AcquireReaderLock(1000);
                    try
                    {
                        //Создание копии объета сотрудника
                        Employee tEmpl = new Employee();
                        //Чтение имени
                        tEmpl.fname = this.oEmpl.fname;
                        Thread.Sleep(rnd.Next(100));
                        //Чтение фамилии
                        tEmpl.lname = this.oEmpl.lname;
                        Thread.Sleep(rnd.Next(100));
                        //Чтение возраста
                        tEmpl.Age = this.oEmpl.Age;
                        Thread.Sleep(rnd.Next(100));
                        return tEmpl;
                    }
                    finally
                    {
                        rwl.ReleaseReaderLock();
                    }
                }
                catch(Exception)
                {
                    return null;
                }

            }
            set
            {
                //запись данных о сотруднике
                try
                {
                    rwl.AcquireWriterLock(1000);
                    try
                    {
                        //Запись имени сотрудника
                        this.oEmpl.fname = value.fname;
                        Thread.Sleep(rnd.Next(500));
                        //Запись фамилии сотрудника
                        this.oEmpl.lname = value.lname;
                        Thread.Sleep(rnd.Next(500));
                        //Запись возраста сотрудника
                        this.oEmpl.Age = value.Age;
                        Thread.Sleep(rnd.Next(500));
                    }
                    finally
                    {
                        rwl.ReleaseWriterLock();
                    }
                }
                catch(Exception)
                {
                }

            }
        }

        #endregion
    }
 

Автор: Аленка 17.7.2006, 07:53
Ну ты же сам наверно все понимаешь smile  (Это я насчет скомканности)
Ты увеличил время, через которое методы обращаются к данным, поэтому, возможно, они и успевают закончить работу, не прерываясь другими методами.
 

Автор: YoungMan 17.7.2006, 11:42
Но время на запись (в среднем) значительно больше времени чтения чтения, т.е. больше "читателей" могут влезть.

Или я не правильно понимаю?

Может подскажешь тогда smile. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)