Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизованное свойство, пытаюсь разобраться, появились вопросы 
:(
    Опции темы
DEER
Дата 20.6.2006, 10:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



господа. возникла пара вопросов, касающихся синхронизации методов в C#.
точнее мне надо синхронизировать свойство (get и set как я понимаю) некоего объекта.
поиском пользовался кое что нашел полезное. (вот сообщение Domestic Cat'а)
Осталось упочнить детали.
итак.
суть моёй задачки такова
Цитата
Реализуйте 'синхронное' 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-е правило из задания. Я просто не до конца его понял.

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

Это сообщение отредактировал(а) DEER - 20.6.2006, 10:35


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
ivashkanet
Дата 20.6.2006, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



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

Не должно быть у тебя задержки. Доместикс делал ее для емуляции процесса выпивания пива
Пока все. В остальном я пас   smile 
 
PM MAIL WWW ICQ   Вверх
DEER
Дата 20.6.2006, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



ivashkanet,  спасиба, но она должна быть по заданию, я просто не всё задание написал  smile  


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
mr.DUDA
Дата 20.6.2006, 11:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



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

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


--------------------
user posted image
PM MAIL WWW   Вверх
DEER
Дата 20.6.2006, 11:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



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 
на счет того что она решена... я это предполагал, но решить надо самому.это типа тестовое задание 


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
mr.DUDA
Дата 20.6.2006, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



А какой глубокий смысл делать ожидание, если вход в lock и так ожидает выхода из lock другого потока ?

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


--------------------
user posted image
PM MAIL WWW   Вверх
DEER
Дата 20.6.2006, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



ну вот я и спрашиваю. правильно я их использую или нет?

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


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
Аленка
Дата 21.6.2006, 09:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 54
Регистрация: 16.6.2006

Репутация: нет
Всего: нет



А как без локов получилось? Если получилось?

Код

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


 
PM   Вверх
DEER
Дата 21.6.2006, 11:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



Цитата
А как без локов получилось? Если получилось?

Совсем без локов не получилось...
кое что похожее на правду получилось как раз с 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)
                {
                    //
                }            
            }
        }
    }

 


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
Аленка
Дата 21.6.2006, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 54
Регистрация: 16.6.2006

Репутация: нет
Всего: нет



А как тестируешь?

Код

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


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

Это сообщение отредактировал(а) Аленка - 21.6.2006, 11:31
PM   Вверх
DEER
Дата 21.6.2006, 16:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 749
Регистрация: 12.4.2005
Где: г. Рязань

Репутация: 1
Всего: 13



тест не очень получился...
Код

        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();
        }
 


--------------------
 
PM MAIL WWW ICQ MSN   Вверх
YoungMan
Дата 13.7.2006, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 13.7.2006

Репутация: нет
Всего: нет



Если использовать код, приведенный 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 опущен)

Вопрос: как от этого избавиться? 
PM MAIL   Вверх
YoungMan
Дата 13.7.2006, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 13.7.2006

Репутация: нет
Всего: нет



и еще вопрос, почему если убрать конструкцию 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)
 
PM MAIL   Вверх
YoungMan
Дата 14.7.2006, 05:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 13.7.2006

Репутация: нет
Всего: нет



На мой взгляд класс 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);
            }
        }
    }
 
PM MAIL   Вверх
Аленка
Дата 14.7.2006, 19:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 54
Регистрация: 16.6.2006

Репутация: нет
Всего: нет



Цитата(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 похоже просто позволяет избежать потенциальных ошибок при обращении к уже используемому монитору. Синхронизировать надо использование монитора.
И скомканные данные получаются, потому что нет синхронизации.   

Это сообщение отредактировал(а) Аленка - 14.7.2006, 20:04
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0896 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.