lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 08:38
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Знаешь, что такое Очень Плохая Вещь?

ГВ>Это вот она:
СГ>>C#:
  System.Monitor.Enter(this);


Здравствуйте, Дарней, Вы писали:

Д> Вот придёт кому-то в голову синхронизироваться на этом же объекте, но в другом месте и в других целях — и всё, приплыли.


Ну, дуракам закон не писан. А Вы ещё спрашивали в чём разница между обычными языками (типа C#) и языками поддерживающими парадигму активных объектов (Active Oberon, Zonnon,...). Разница в том, что залочится в C# можно на любом (чужом) объекте (быть может, на ровном месте неожиданно заработав deadlock), а в Active Oberon — только на самом себе (только на this).

Лочиться только на самом себе логически следует из объединения ООП и многопоточности:
1) Все данные инкапсулированы внутри объектов.
2) Доступ к любым данным осуществляется только с помощью методов объекта.
3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы (т.е такие методы, блоки кода в которых залочены на this).
Re: lock (this)
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 09:28
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:
Д>> Вот придёт кому-то в голову синхронизироваться на этом же объекте, но в другом месте и в других целях — и всё, приплыли.

СГ>Ну, дуракам закон не писан. А Вы ещё спрашивали в чём разница между обычными языками (типа C#) и языками поддерживающими парадигму активных объектов (Active Oberon, Zonnon,...). Разница в том, что залочится в C# можно на любом (чужом) объекте (быть может, на ровном месте неожиданно заработав deadlock), а в Active Oberon — только на самом себе (только на this).


И это хорошо? Вот у меня есть статический метод:
public static void M()
{
    lock(_syncObj)
    {
        ...
    }
}

Ну и как с этим бороться если lock будет разрешаться только на this?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[2]: lock (this)
От: marat321  
Дата: 29.03.06 09:33
Оценка:
Здравствуйте, ie, Вы писали:

ie>И это хорошо? Вот у меня есть статический метод:


ie>Ну и как с этим бороться если lock будет разрешаться только на this?


В абяроне есть статические методы?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
silent
Re[3]: lock (this)
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 09:38
Оценка:
Здравствуйте, marat321, Вы писали:

M>Здравствуйте, ie, Вы писали:


ie>>И это хорошо? Вот у меня есть статический метод:


ie>>Ну и как с этим бороться если lock будет разрешаться только на this?


M>В абяроне есть статические методы?




А вот в C# с которым приводится сравнение, есть.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[2]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 09:42
Оценка:
Здравствуйте, ie, Вы писали:

ie>Ну и как с этим бороться если lock будет разрешаться только на this?


Если у класса есть статические методы, значит класс используется в роли модуля. Роль this отдаётся типу класса typeof():
public sealed class MyClass
{
  private static Data data;

  public static void M ()
  {
    lock (typeof(MyClass))
    {
      //эксклюзивная работа с data
      ...
    }
  }
}
Re[2]: lock (this)
От: Oyster Украина https://github.com/devoyster
Дата: 29.03.06 09:43
Оценка: :))) :))) :)
Здравствуйте, ie, Вы писали:

ie>И это хорошо? Вот у меня есть статический метод:

...
ie>Ну и как с этим бороться если lock будет разрешаться только на this?

Тёмная силы сторона статическими методами завладела. Объекты активные только используй ты
Re[3]: lock (this)
От: Oyster Украина https://github.com/devoyster
Дата: 29.03.06 09:46
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Если у класса есть статические методы, значит класс используется в роли модуля. Роль this отдаётся типу класса typeof():


Читаем классику: A Special Dr. GUI: Don't Lock Type Objects!
Re[3]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 09:52
Оценка:
Здравствуйте, marat321, Вы писали:

M>В абяроне есть статические методы?


Есть, только называются они просто обычными процедурами.

Oberon — модульная система, все процедуры расположены в модулях. Модуль играет роль объекта-синглетона. Он может инкапсулировать любые данные. Доступ к этим данным осуществляется с помощью процедур этого модуля. Процедуры могут быть эксклюзивными для этого модуля. Так что, в этом смысле (эксклюзивного доступа к данным), разница между объектом и модулем отсутствует: в методах объекта лочатся на this, в процедурах модуля лочаться на сам модуль.

Пример:
PROCEDURE DoSmth;
BEGIN {EXCLUSIVE}
  ...
END DoSmth;

если DoSmth — это метод объекта, то {EXCLUSIVE} — обозначает лок на this,
если DoSmth — это просто обычная процедура из модуля MyModule, то {EXCLUSIVE} — обозначает лок на MyModule.
Re[4]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 10:15
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Читаем классику: A Special Dr. GUI: Don't Lock Type Objects!


Ха-ха-ха, из-за того что в C# разрешено блокировать не только самого себя (this или typeof(Me)), но и любого другого тоже вот такое безобразие и возникает! Если бы было разрешено блокировать только самого себя (this или typeof(Me)), всё было бы чики-пуки. Разрешение блокировать чужой объект (а не лишь самого себя), это всё равно что разрешение использовать goto — та же нелокальность последствий. Хотя нет, это даже хуже чем goto — это goto-наоборот, что-то из оперы COMING FROM
Re: Задача об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 10:29
Оценка:
Я тут у себя на работе сочинил небольшой задачник для проведения собеседований,
вот задача как раз на тему этой ветки форума:


Задача об очереди

Напишите реализацию методов Enqueue и Dequeue.

Указание
Для синхронизации потоков, где это нужно, используйте:
• lock (expression)
• System.Threading.Monitor.Wait (object obj);
• System.Threading.Monitor.PulseAll (object obj);

Время: 5 минут


namespace EmployeeTest
{
    public interface IQueue
    {
        void Enqueue (object element);
        object Dequeue ();
    }

    public sealed class MyQueue: IQueue
    {
        private sealed class Item
        {
            public object element;
            public Item next;
            public Item (object element)
            {
                this.element = element;
            }
        }

        private Item head;
        private Item tail;

        public void Enqueue (object element)
        {
            // Добавить элемент в хвост очереди.
            // Операция должна быть безопасна в условиях многопоточного использования.
        }

        public object Dequeue ()
        {
            // Если очередь пуста, то ждать (спать) до тех пор пока кто-то другой 
            // (из другого потока) добавит элемент в очередь.
            // Извлечь элемент из головы очереди и вернуть его из функции.
            // Операция должна быть безопасна в условиях многопоточного использования.
            return null;
        }
    }
}

не торопитесь смотреть решение (оно в следующем сообщении) попробуйте сначала решить задачу самостоятельно...
Re[2]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 10:32
Оценка:
Вот...


Решение задачи об очереди

namespace EmployeeTest
{
    public interface IQueue
    {
        void Enqueue (object element);
        object Dequeue ();
    }

    public sealed class MyQueue: IQueue
    {
        private sealed class Item
        {
            public object element;
            public Item next;
            public Item (object element)
            {
                this.element = element;
            }
        }

        private Item head;
        private Item tail;

        public void Enqueue (object element)
        {
            lock (this)
            {
                Item a = new Item(element);
                if (this.tail != null) this.tail.next = a; else this.head = a;
                this.tail = a;
                System.Threading.Monitor.PulseAll(this);
            }
        }

        public object Dequeue ()
        {
            lock (this)
            {
                while (this.head == null) System.Threading.Monitor.Wait(this);
                object r = this.head.element;
                this.head = this.head.next;
                if (this.head == null) this.tail = null;
                System.Threading.Monitor.PulseAll(this);
                return r;
            }
        }
    }
}

Re[3]: lock (this)
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 10:36
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, ie, Вы писали:


ie>>Ну и как с этим бороться если lock будет разрешаться только на this?


СГ>Если у класса есть статические методы, значит класс используется в роли модуля. Роль this отдаётся типу класса typeof():


Но все-таки возвращаясь к первоначальной постановке. Допустим я хочу эксклюзивно владеть объектом. Т.е. объект сам не thread-safe, но я хочу использовать его из нескольких потоков. Тогда как?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[3]: Решение задачи об очереди
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 10:43
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Решение задачи об очереди


Красота! Только вот я не могу никак в вашем решении узнать, является ли очередь пустая или нет, а при попытке взять из нее что-нибудь, виснем и возможно надолго.
Собеседование заваленно
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[4]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 10:57
Оценка:
Здравствуйте, ie, Вы писали:

ie>Но все-таки возвращаясь к первоначальной постановке. Допустим я хочу эксклюзивно владеть объектом. Т.е. объект сам не thread-safe, но я хочу использовать его из нескольких потоков. Тогда как?


Обзовём этот объект словом — data.

Тогда возвращаемся обратно к основным принципам ООП объединённого с многопоточностью:
1) Все данные инкапсулированы внутри объектов.
2) Доступ к данным осуществляется только с помощью методов объекта.
3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы.

Процесс мышления таков:
1) data — это теперь данные, надо их инкапсулировать в какой-то объект MyData.
2) Снаружи доступ к данным осуществляется только с помощью методов объекта MyData.
3) Синхронизированный доступ осуществляется эксклюзивными методами объекта MyData.

Резюме:
Написать thread-safe объект-обёртку MyData над объектом data и работать через него.
Re: lock (this)
От: WolfHound  
Дата: 29.03.06 11:03
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

Читай до просветления
Потоковобезопасный std::vector&lt;&gt;
Автор: MTdev
Дата: 22.03.06
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 11:11
Оценка:
Здравствуйте, ie, Вы писали:

ie>Красота! Только вот я не могу никак в вашем решении узнать, является ли очередь пустая или нет, а при попытке взять из нее что-нибудь, виснем и возможно надолго.


Это не решение "виновато", а такое было условие задачи. Условие задачи намеренно сделано очень простым, чтобы испытуемый успел решить эту задачу (и ещё ряд других) во время собеседования не слишком при этом утомив и того кто его экзаменует.

Если бы я сформулировал её так:
public interface IQueue
{
  void Enqueue (object element);
  object Dequeue ();
  bool IsAvailable {get;} // не пуста ли очередь?
  bool BlockingMode {get; set;} // снять/установить/проверить блокирующий режим.
  // В случае если BlockingMode = false, то Dequeue должна выдавать исключение когда очередь пуста
  // В случае если BlockingMode = true, то Dequeue должна блокировать поток до тех пор пока очередь пуста
}

то мне пришлось бы дать испытуемому чуток побольше времени, но ничего принципиально нового бы о нём я бы не узнал. Ведь если он решит первую задачу, то решит и вторую (аналогичную), так чего время зря тянуть?
Re[5]: lock (this)
От: Cyberax Марс  
Дата: 29.03.06 11:12
Оценка:
Сергей Губанов wrote:
> 1) *Все* данные инкапсулированы внутри объектов.
> 2) Доступ к данным осуществляется *только* с помощью методов объекта.
> 3) Для синхронизированного (эксклюзивного) доступа к данным используются
> *эксклюзивные методы*.
Вы только что описали аппартаментную (appartament) потоковую модель COM.
Рассказать какие с ней проблемы возникают?
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[6]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 11:18
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Рассказать какие с ней проблемы возникают?


Расскажите.
Re[5]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 11:24
Оценка: +1
СГ>
СГ>  bool IsAvailable {get;} // не пуста ли очередь?
СГ>


Кстати, проверять пуста очередь или не пуста перед выполнением Dequeue — не очень осмысленное занятие, ведь в промежуток времени между вызовами IsAvailable и Dequeue очередь может успеть опустошить кто-то другой...
Re[5]: lock (this)
От: Oyster Украина https://github.com/devoyster
Дата: 29.03.06 11:26
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Ха-ха-ха, из-за того что в C# разрешено блокировать не только самого себя (this или typeof(Me)), но и любого другого тоже вот такое безобразие и возникает! Если бы было разрешено блокировать только самого себя (this или typeof(Me)), всё было бы чики-пуки. Разрешение блокировать чужой объект (а не лишь самого себя), это всё равно что разрешение использовать goto — та же нелокальность последствий. Хотя нет, это даже хуже чем goto — это goto-наоборот, что-то из оперы COMING FROM


Но мы-то говорим о C#...
Re[6]: lock (this)
От: Kluev  
Дата: 29.03.06 11:31
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Сергей Губанов wrote:

>> 1) *Все* данные инкапсулированы внутри объектов.
>> 2) Доступ к данным осуществляется *только* с помощью методов объекта.
>> 3) Для синхронизированного (эксклюзивного) доступа к данным используются
>> *эксклюзивные методы*.
C>Вы только что описали аппартаментную (appartament) потоковую модель COM.
C>Рассказать какие с ней проблемы возникают?

Какие?
Re: lock (this)
От: alexeiz  
Дата: 29.03.06 11:41
Оценка:
СГ>Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>Знаешь, что такое Очень Плохая Вещь?

ГВ>>Это вот она:
СГ>>>C#:
СГ>
СГ>  System.Monitor.Enter(this);
СГ>


СГ>Здравствуйте, Дарней, Вы писали:


Д>> Вот придёт кому-то в голову синхронизироваться на этом же объекте, но в другом месте и в других целях — и всё, приплыли.


А это, кстати, интересный вопрос. Вот в .NET у каждого объекта сделали sync block, чтобы каждому объекту можно было сделать lock(this). А потом выяснилось, что это очень и очень плохо делать lock(this). Начали рекомендовать практику введения отдельного синхронизирующего объекта, т.е.
class MySyncClass
{
    object sync_obj = new object();
    public void foo()
    {
        lock (sync_obj)
        {
            // modify me
        }
    }
}

Спрашивается, зачем у каждого объекта sync block, если он в подавляющем большинстве случаев не используется, а используем мы для синхронизации другой, специально созданный для этого объект, для которого можно было бы иметь специальный класс. И только этот класса должен иметь sync block. У остальных классов от sync block'а можно было бы избавиться. А sync block между прочим 4 байта требует.
Re[3]: Решение задачи об очереди
От: GlebZ Россия  
Дата: 29.03.06 12:17
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

УжасЪ
Сергей, предлагаю вам в качестве домашнего задания решить данную задачу вообще без объектов синхронизации. Максимум, InterlockedExchange, чтобы вам полегче было.
Re[3]: Решение задачи об очереди
От: minorlogic Украина  
Дата: 29.03.06 13:00
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Вот...


А в Dequeue () разве мы не поймали дедлок ?

Как кто то может что то добавить , если мы залочили все выполнение ? Или я чет в механизмах шарповских не понимаю
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[4]: Monitor
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 13:47
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>А в Dequeue () разве мы не поймали дедлок ?


M>Как кто то может что то добавить , если мы залочили все выполнение ? Или я чет в механизмах шарповских не понимаю


Это не шарповские механизмы, и даже не дотнетные, это называется Монитор.

Шарповский lock (obj) {...} — это синтаксический сахар над:
System.Threading.Monitor.Enter(obj)
try
{
  ...эксклюзивный блок кода
}
finally
{
  System.Threading.Monitor.Exit(obj);
}

У монитора, кроме Enter(obj) и Exit(obj) есть еще Wait(obj) и PulseAll(obj), которые можно вызывать только находясь внутри эксклюзивного блока кода. Wait — усыпляет поток до тех пор пока кто-то другой не вызовет PulseAll. Уснувший по Wait поток считается (временно) покинувшим эксклюзивный блок, так что эксклюзивный блок становится вновь доступен для проникновения в него другого потока, поработав внутри эксклюзивного блока другой поток, уходя, должен вызвать PulseAll для того чтобы разбудить уснувшие по Wait другие потоки. Итак, на вход в эксклюзивный блок есть две очереди. Одна очередь образуется на барьере Enter, а другая очередь — это уже вошедшие ранее в эксклюзивный блок потоки, но уснувшие внутри него по Wait.
        public object Dequeue ()
        {
            // перед этой командой потоки ставятся в очередь: внутрь вход по одному!
            lock (this)
            {
                // Проникнув внутрь эксклюзивного блока, поток проверяет очередь на непустоту,
                // если она пуста - засыпает. Как только он засыпает по Wait, то объект this становится
                // вновь доступен для других потоков. Раз так, то какой-то другой поток может вызвать
                // метод Enqueue и сделать очередь непустой. В конце метода Enqueue зовётся PulseAll.
                // Сработавший PulseAll будит уснувшие на этом объекте потоки. Разбуженные потоки вновь
                // впускаются внутрь эксклюзивного блока (по одному), 
                // из которого они были временно выведены на время своего сна
                while (this.head == null) System.Threading.Monitor.Wait(this);

                object r = this.head.element;
                this.head = this.head.next;
                if (this.head == null) this.tail = null;
                System.Threading.Monitor.PulseAll(this);
                return r;
            }
        }


На мониторах построен язык Active Oberon:

Active Oberon Language Report: http://bluebottle.ethz.ch/languagereport/index.html


В этом языке Monitor.Enter/Exit — обозначаются блоком

BEGIN {EXCLUSIVE}
...
END;

PulseAll — подразумевается перед выходом из каждого {EXCLUSIVE} блока.

Monitor.Wait обозначается инструкцией AWAIT (condition)

Итого, для синхронизации, в язык введено два дополнительных служебных слова EXCLUSIVE и AWAIT — с помощью них реализуются все механизмы синхронизации:
Synchonization Examples: http://bluebottle.ethz.ch/languagereport/node8.html


Вот аналог того буфера:
MODULE Buffers;

CONST
  BufLen = 256;
  
TYPE
  (* Buffer- First-in first-out buffer *)

  Buffer* = OBJECT
    VAR
      data: ARRAY BufLen OF INTEGER;
      in, out: LONGINT;
      
    (* Put - insert element into the buffer *)
    
    PROCEDURE Put* (i: INTEGER);
    BEGIN {EXCLUSIVE}
      AWAIT ((in + 1) MOD BufLen # out);  (*AWAIT ~full *)
      data[in] := i;
      in := (in + 1) MOD BufLen
    END Put;
    
    (* Get - get element from the buffer *)
    
    PROCEDURE Get* (VAR i: INTEGER);
    BEGIN {EXCLUSIVE}
      AWAIT (in # out);  (*AWAIT ~empty *)
      i := data[out];
      out := (out + 1) MOD BufLen
    END Get;
    
    PROCEDURE & Init;
    BEGIN
      in := 0; out := 0;
    END Init;
  
  END Buffer;

END Buffers.
Re[4]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 13:54
Оценка: :)
Здравствуйте, GlebZ, Вы писали:

GZ>Сергей, предлагаю вам в качестве домашнего задания решить данную задачу вообще без объектов синхронизации. Максимум, InterlockedExchange, чтобы вам полегче было.


На InterlockedExchange и, тем более, вообще без объектов синхронизации эту задачу решить нельзя. Какую-то другую — можно, эту — нет.
Re[6]: Решение задачи об очереди
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 14:16
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>>
СГ>>  bool IsAvailable {get;} // не пуста ли очередь?
СГ>>


СГ>Кстати, проверять пуста очередь или не пуста перед выполнением Dequeue — не очень осмысленное занятие, ведь в промежуток времени между вызовами IsAvailable и Dequeue очередь может успеть опустошить кто-то другой...


В том то и беда. Что вызов Dequeue может привести к бесконечному ожиданию, что на самом деле не допустимо. Решение разработчиков стандартной (System.Collection.Queue) очереди мне кажется более логичным. Но как я помню из ваших предыдущих постов, бросать исключение плохо, поэтому даже не знаю получится ли у вас красивое разрешение этой ситуации.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re[5]: Monitor
От: minorlogic Украина  
Дата: 29.03.06 14:46
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Это не шарповские механизмы, и даже не дотнетные, это называется Монитор.


[skiped]

Спасибо , тогда более не менеее понятно! Чувствую надо будет ознакомиться
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[7]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.03.06 14:47
Оценка:
Здравствуйте, ie, Вы писали:

ie>В том то и беда. Что вызов Dequeue может привести к бесконечному ожиданию, что на самом деле не допустимо.


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

ie>Решение разработчиков стандартной (System.Collection.Queue) очереди мне кажется более логичным. Но как я помню из ваших предыдущих постов, бросать исключение плохо, поэтому даже не знаю получится ли у вас красивое разрешение этой ситуации.


Не блокирующий вызов не кидающий исключений в случае пустой очереди? Да элементарно:
bool Dequeue (out object obj);



if (queue.Dequeue(out x))
{
  ...
}
else
{
  ... очередь оказалась пустой
}
Re[7]: lock (this)
От: Cyberax Марс  
Дата: 29.03.06 15:57
Оценка:
Kluev wrote:
> C>Вы только что описали аппартаментную (appartament) потоковую модель COM.
> C>Рассказать какие с ней проблемы возникают?
> Какие?
1. Межпоточный маршаллинг — с языковой поддержкой он, конечно, будет
прозрачным и более эффективным цикла сообщений в Винде. Но все же...

2. Интересные проблемы со сроками жизни аппартамента и ссылок на его
объекты в других потоках. Хорошо объяснено в
http://www.rsdn.ru/article/atl/atlsingleton.xml
Автор(ы): Иван Андреев
Дата: 03.08.2003
Описание шаблона проектирования синглетон очень простое — синглетон представляет собой единственный экземпляр класса, с которым работают все клиенты. Применительно к COM шаблон проектирования синглетон гарантирует, что все вызовы CoCreateInstance будут возвращать указатель на интерфейс единственного экземпляра компонента. Удобство использования таких компонентов/классов заключается в том, что клиенты работают с одним и тем же экземпляром, а значит, получают доступ к разделяемому состоянию этого экземпляра. Несмотря на простое описание, не существует "идеальной" реализации этого шаблона ни в языке С++, ни для COM-объектов. Связано это с тем, что любая существующая реализация имеет некоторые ограничения и не может выступать в роли "универсальной" реализации на все случаи жизни.


3. Слишком грубая структуризация — несколько потоков не могут
одновременно использовать ресурсы одного аппартамента, даже если они не
связаны друг с другом.

4. Остается возможность дедлоков, несмотря на то, что код фактически
однопоточный.

Из плюсов: очень эффективно в некоторых случаях, так как не нужны
блокировки ну и писать однопоточные приложения значительно проще.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re: lock (this)
От: Дарней Россия  
Дата: 29.03.06 16:25
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы (т.е такие методы, блоки кода в которых залочены на this).


и всё-таки, я так и не понял толком — лочатся все методы объекта или только специальным образом помеченные?
и второй вопрос — зачем писать в явном виде вот это, вместо простого lock() {}?
System.Monitor.Enter(this);
  try
  {
  }
  finally
  {
    System.Monitor.PulseAll(this);
    System.Monitor.Exit(this);
  }
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[8]: Решение задачи об очереди
От: ie Россия http://ziez.blogspot.com/
Дата: 29.03.06 16:36
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

ie>>В том то и беда. Что вызов Dequeue может привести к бесконечному ожиданию, что на самом деле не допустимо.


СГ> В некоторых задачах очень даже допустимо, даже необходимо по логике работы. Например в моей программе есть такое место, когда распознаватель речи обратившись за очередной порцией данных отправляется в спячку если эта порция данных ещё не была к этому времени получена. Как только она получается, он автоматически будится просто от того, что в очередь произведена запись.


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

ie>>Решение разработчиков стандартной (System.Collection.Queue) очереди мне кажется более логичным. Но как я помню из ваших предыдущих постов, бросать исключение плохо, поэтому даже не знаю получится ли у вас красивое разрешение этой ситуации.


СГ>Не блокирующий вызов не кидающий исключений в случае пустой очереди? Да элементарно:

СГ>
СГ>bool Dequeue (out object obj);
СГ>


Я бы в таком случае принял решение создания 2х методов.

Кидающий исключение:
СГ>
СГ>object Dequeue();
СГ>

И не кидающий его:
СГ>
СГ>bool TryDequeue(out object obj);
СГ>
... << RSDN@Home 1.2.0 alpha rev. 0>>
Превратим окружающую нас среду в воскресенье.
Re: lock (this)
От: Кодт Россия  
Дата: 29.03.06 19:01
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

Д>> Вот придёт кому-то в голову синхронизироваться на этом же объекте, но в другом месте и в других целях — и всё, приплыли.


СГ>Ну, дуракам закон не писан. А Вы ещё спрашивали в чём разница между обычными языками (типа C#) и языками поддерживающими парадигму активных объектов (Active Oberon, Zonnon,...). Разница в том, что залочится в C# можно на любом (чужом) объекте (быть может, на ровном месте неожиданно заработав deadlock), а в Active Oberon — только на самом себе (только на this).


Сергей, а как в Обероне решается вот такая задача:
TYPE ClassA = CLASS
  ptrB: POINTER TO ClassB;
END;
TYPE ClassB = CLASS
  ptrA: POINTER TO ClassA;
END;


FUNCTION Construct(): POINTER TO ClassA;
BEGIN
  ptrA := NEW ClassA;
  ptrA.ptrB := NEW ClassB;
  ptrA.ptrB.ptrA := ptrA;
  Construct := ptrA;
END;


PROCEDURE ClassA.foo;
BEGIN {exclusive}
  .....
  this.ptrB.foo();
  .....
END;
PROCEDURE ClassB.foo;
BEGIN {exclusive}
  .....
END;


PROCEDURE ClassB.bar;
BEGIN {exclusive}
  .....
  this.ptrA.bar();
  .....
END;
PROCEDURE ClassA.bar;
BEGIN {exclusive}
  .....
END;

(Если чего напутал в синтаксисе — извини).

И теперь предположим, что два потока одновременно влезли в эту пару — один через ClassA.foo(), другой через ClassB.bar(). Всё, дедлок. Хотя объекты блокировали только себя.

По-хорошему, тут нужно всё переписывать: разбивать ClassA.foo и ClassB.bar, чтобы передача управления за пределы критической секции разблокировала объект. Естественно, не нарушая его инвариант...
Перекуём баги на фичи!
Re: lock (this)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.03.06 23:28
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Лочиться только на самом себе логически следует из объединения ООП и многопоточности:

СГ>1) Все данные инкапсулированы внутри объектов.
СГ>2) Доступ к любым данным осуществляется только с помощью методов объекта.
СГ>3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы (т.е такие методы, блоки кода в которых залочены на this).

А как лочить несколько объектов за раз? То есть, например, вот такая ситуация:

Имеем два объекта (a1 и a2). И два объекта-пользователя (b и c). Объекту b нужно лочить a1 и a2, а объекту c — только a2. Например, b перекачивает какие-то данные из a1 в a2, а c — только обновляет a2.

Если мы можем опираться только на самоблокировку объекта, тогда получается, что нужно организовать какой-то промежуточный d, у которого будет два exclusive-метода: meth_for_a1_a2 и meth_for_a2. Хорошо, мы перенаправим вызовы b и c на некий d. А потом у нас появится третий пользователь, например e, которому нужно будет лочить только a1. Будем переделывать d?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: lock (this)
От: Кодт Россия  
Дата: 29.03.06 23:52
Оценка: +3
Здравствуйте, Сергей Губанов, Вы писали:

<>

Некоторый оффтопик.

В очередной раз дискуссия переходит в режим противостояния. И вот почему.
Ты предлагаешь серебряные пули. А серебряных пуль-то, на самом деле, не существует. Есть много видов обычных пуль, которыми нужно стрелять по соответствующим целям.

У самоблокировок есть своя ниша. У блокировок сторонних объектов — другая ниша.
Скажем, в СУБД предмет блокировок — не сами активности сервера, и не транзакции, а участки БД, т.е. пассивные объекты. Делать таблицы активностями просто смысла нет.

Кстати, джентельмены! Чтобы не доводить до флейма: когда приводите контрпримеры — старайтесь не просто "доказать от противного", но и
— очертить круг целей
— показать, какие пули предназначены для этих целей
Перекуём баги на фичи!
Re[2]: lock (this)
От: Severn Россия  
Дата: 30.03.06 03:30
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ> Будем переделывать d?

Зачем? d синхронизирует свои данные — по сути это некая дополнителная обработка между обращениями к a1 и a2.


    public class A1
    {
        public Smth Smth
        {
            get { return new Smth("Smth from A1"); }
        }

        public void DoA1(A2 a2)
        {
            Smth s = a2.Smth;
            lock (this)
            {
                // некие операции с иполоьзованием this и s
            }
        }
    }

    public class A2
    {
        public Smth Smth
        {
            get { return new Smth("Smth from A2"); }
        }

        public void DoA2(A1 a1)
        {
            Smth s = a1.Smth;
            lock (this)
            {
                // некие операции с иполоьзованием this и s
            }
        }
        public void MethForA2()
        {
            lock (this)
            {
                // некие операции с иполоьзованием this
            }
        }
    }

    public class D
    {
        public void MethForA1A2(A1 a1, A2 a2)
        {
            // синхронизирует все операцию целиком, а не данные a1 и a2
            // если additionalProcessing нет, то просто переносим все либо в A1 либо в A2
            lock (this)
            {
                a1.DoA1(a2);
                additionalProcessing(a1,a2);
                a2.DoA2(a1);
            }
        }

        private void additionalProcessing(A1 a1, A2 a2)
        { }
    }

Подправил форматирование — включил раскраску кода. — Кодт
Re[9]: Решение задачи об очереди
От: Severn Россия  
Дата: 30.03.06 03:39
Оценка:
Здравствуйте, ie, Вы писали:

ie>Кидающий исключение:

СГ>>
СГ>>object Dequeue();
СГ>>

ie>И не кидающий его:
СГ>>
СГ>>bool TryDequeue(out object obj);
СГ>>


Это имхо неверно — ислпьзовать два разных подхода. Никогда не знаешь, что от метода ожидать — придется и if'ы лепить и try.
Лучше уж сделать
object Dequeue();

НЕ кидающий исключение и при случае возвращающий null. Дополнительный if все равно придется ставить, также как и в bool TryDequeue(out object obj), а писанины меньше
Re[3]: Решение задачи об очереди
От: Severn Россия  
Дата: 30.03.06 03:44
Оценка:
Здравствуйте, Severn, Вы писали:

S>Здравствуйте, Геннадий Васильев, Вы писали:


Кстати, неплохая статейка есть: здесь. Правда имхо не нужно все понимать так радикально, как там написано.
Re[9]: Решение задачи об очереди
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.03.06 07:40
Оценка:
Здравствуйте, ie, Вы писали:

ie> это должна быть коллекция "под конкретную задачу"


Естественно.
Re[2]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.03.06 07:57
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>и всё-таки, я так и не понял толком — лочатся все методы объекта или только специальным образом помеченные?


Лочатся только блоки кода помеченные директивой {EXCLUSIVE}. Внутри одной процедуры может быть несколько таких блоков.
PROCEDURE DoSmth;
BEGIN
  ...
  BEGIN {EXCLUSIVE} this.a := a1; this.b := b1 END; (* значения измененяются одной атомарной операцией *)
  ...
  BEGIN {EXCLUSIVE} this.a := a2; this.b := b2 END; (* значения измененяются одной атомарной операцией *)
  ...
END DoSmth;


Д>и второй вопрос — зачем писать в явном виде вот это, вместо простого lock() {}?


Я не настаиваю на этом. Можете писать как хотите:
System.Threading.Monitor.Enter(this);
try
{
  ...
  ...
  ...
  return x;
}
finally
{
  System.Threading.Monitor.PulseAll(this);
  System.Threading.Monitor.Exit(this);
}

или через lock:
lock (this)
{
  try
  {
    ...
    ...
    ...
    return x;
  } 
  finally
  {
    System.Threading.Monitor.PulseAll(this);
  }
}

эти тексты эквивалентны.

Естественно, если Вы не пользуетесь связкой Monitor.Wait(this) / Monitor.PulseAll(this), то lock — более "красиво выглядит".
Re[2]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.03.06 08:16
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Всё, дедлок.


Естественно, разрешение блокировать только себя — не панацея от дедлоков. Выгода — в локальности ошибки: чтобы понять в чём ошибка достаточно посмотреть на исходный текст эксклюзивных методов объектов классов A и B. Эксклюзивных методов у них 4 штуки — надо критически просмотреть текст 4 процедур. А если разрешить лочиться на ком угодно и где угодно, то ошибку искать придётся неизвестно где — по всему тексту программы, а не в 4 процедурах. С учётом модульных систем (когда загрузился чей-то посторонний модуль и что-то чужое залочил) найти ошибку будет очень трудоёмко.

Можно провести следующую аналогию. Забудем про потоки и поговорим про обычное ООП. Пусть мы решили спрятать данные внутри объектов и давать к ним доступ только через методы. Сочиним два класса A и B. Пусть в классе А есть метод, который вызывает метод класса В, а тот вызывает этот же метод класса А -> stack otherflow. Чтобы понять в чём ошибка достаточно посмотреть на исходный текст этих методов классов A и B, а не изучать текст всей программы, что было бы будь поля объектов доступны для непосредственного редактирования (не инкапсулированы).
Re[3]: lock (this)
От: Дарней Россия  
Дата: 30.03.06 08:18
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Лочатся только блоки кода помеченные директивой {EXCLUSIVE}. Внутри одной процедуры может быть несколько таких блоков.


получается, что это просто синтаксический сахар, ничем принципиально не отличающийся от сишарпного lock
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[2]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.03.06 08:39
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Будем переделывать d?


Да, переделаем...

d.do_a1();
d.do_a2();
d.do_a12();

d.do_a1();
d.do_a2();
d.do_a3();
d.do_a12();
d.do_a13();
d.do_a23();
d.do_a123();

...но это не особо сложно.

Сложнее в случае, когда надо блокировать нечто "по цепочке", т.е. "не отпускать одно не захватив следующее, а захватив следующее, отпускать предыдущее".
Enter(a[i]);
...
Exit(a[i-1]);
...
Enter(a[i+1]);
...
Exit(a[i]);
...

Здесь lock () {...} или BEGIN {EXCLUSIVE} ... END бессильны — нужны семафоры.

В Active Oberon семафоры изготавливают вручную:
TYPE
  Sem* = OBJECT  (* Binary Semaphore *)
      VAR  taken: BOOLEAN
      
      PROCEDURE P*;  (*enter semaphore*)
      BEGIN {EXCLUSIVE}
          AWAIT(~taken); taken := TRUE
      END P;
      
      PROCEDURE V*;  (*leave semaphore*)
      BEGIN {EXCLUSIVE}
          taken := FALSE
      END V;
      
      PROCEDURE & Init;
      BEGIN  taken := FALSE
      END Init;
  END Sem;

Более изощрённая задача — одновременно держать захваченным не 1-2 звена цепочки, а больше.
Re[4]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.03.06 08:50
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>получается, что это просто синтаксический сахар, ничем принципиально не отличающийся от сишарпного lock



Есть одна мелочь (но приятно): По завершении {EXCLUSIVE} блока посылается PulseAll, а по завершении lock — не посылается.

Но есть и принципиальная разница:
В C# кто угодно посторонний может залочить любой другой объект lock (alien) {...}, а в Active Oberon {EXCLUSIVE} — лочит только себя (только this). Это аналогично тому, как если бы в одной системе программирования был бы разрешён непосредственный доступ к полям всех объектов, а в другой системе программирования разрешался бы доступ только к своим собственным полям, а к полям чужих объектов — только через их методы. Думаю, это принципиальная разница: принципиальная локальность возможных ошибок в одной системе и принципиальная нелокальность возможных ошибок в другой системе программирования.
Re[5]: lock (this)
От: Дарней Россия  
Дата: 30.03.06 08:54
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Думаю, это принципиальная разница: принципиальная локальность возможных ошибок в одной системе и принципиальная нелокальность возможных ошибок в другой системе программирования.


Небольшое разумное самоограничение — и никакой принципиальной нелокальности не будет, а ваши волосы станут мягкими и шелковистыми
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[6]: lock (this)
От: SteMage Россия  
Дата: 30.03.06 09:56
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, Сергей Губанов, Вы писали:


СГ>>Думаю, это принципиальная разница: принципиальная локальность возможных ошибок в одной системе и принципиальная нелокальность возможных ошибок в другой системе программирования.


Д>Небольшое разумное самоограничение — и никакой принципиальной нелокальности не будет, а ваши волосы станут мягкими и шелковистыми


Разумное самоограничение ВСЕХ программистов в проекте и все ок. Вот только иногда проще заставить программистов работать со средством разработки принципиально запрещающем что-то делать, нежели добится разумного самоограничения.

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

Хотя бесусловно обсуждаемый момент может быть не достаточно важной причиной для смены средства разработки и т.д.

Но эта особенность ИМХО заслуживает внимания.
Re[7]: lock (this)
От: Дарней Россия  
Дата: 30.03.06 10:44
Оценка:
Здравствуйте, SteMage, Вы писали:

SM>Разумное самоограничение ВСЕХ программистов в проекте и все ок. Вот только иногда проще заставить программистов работать со средством разработки принципиально запрещающем что-то делать, нежели добится разумного самоограничения.


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

SM>Как говорится о коде, который не протестирован с уверенностью можно утверждать только одно он не работает. Надеюсь аналогия понятна.


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

SM>Хотя бесусловно обсуждаемый момент может быть не достаточно важной причиной для смены средства разработки и т.д.


скорее — не может быть достаточно важной причиной. Тем более что надо не только менять средство разработки, но еще и переписывать весь код.

SM>Но эта особенность ИМХО заслуживает внимания.


ни малейшего
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[3]: lock (this)
От: Кодт Россия  
Дата: 30.03.06 11:54
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здесь lock () {...} или BEGIN {EXCLUSIVE} ... END бессильны — нужны семафоры.

СГ>В Active Oberon семафоры изготавливают вручную:

... и потом используют как блокировку внешних объектов.
a[1].sem.p();
process(a[1].data);
                    a[2].sem.p();
                    process(a[2].data);
a[1].sem.v();
                                        a[3].sem.p();
                                        process(a[3].data);
                    a[2].sem.v();
                                        a[3].sem.v();

В общем, как ни пытались отвертеться от опасных приёмов... сами же написали инструментарий для них.

С этой точки зрения нет разницы, является ли примититв синхронизации "семафор" встроенным или рукодельным.

Но вот для сопровождения софта — желательно не давать повод изобретать велосипеды: есть риск ошибок в реализации.

Вот, например, твой семафор. Это двоичный нереентерабельный семафор без политики планирования и без проверок корректного использования. Отсюда:
— риск зависания на двойном захвате: sem.p(); sem.p();
— несбалансированная отдача не отслеживается и может привести в дальнейшем к двойному захвату
— если несколько активностей ждут один семафор, то одна из них может ждать вечно, хотя семафор будет многократно отпущен (и захвачен другими)

Во что разрастётся код семафора, свободный от этих проблем. Вряд ли он будет такой компактный и очевидный.

Потом мы захотим семафор со счётчиком.
Его, конечно, можно сделать на двоичных семафорах; или скопипастим код двоичного, подставив AWAIT(count>0) и count:=count+/-1...

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

Почему сразу нельзя это сделать?
Перекуём баги на фичи!
Re[2]: lock (this)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 30.03.06 12:01
Оценка:
Здравствуйте, alexeiz, Вы писали:


A>Спрашивается, зачем у каждого объекта sync block, если он в подавляющем большинстве случаев не используется, а используем мы для синхронизации другой, специально созданный для этого объект, для которого можно было бы иметь специальный класс. И только этот класса должен иметь sync block. У остальных классов от sync block'а можно было бы избавиться. А sync block между прочим 4 байта требует.


sync block используется не только для блокировки но и например для дефолтного GetHashCode итд
и солнце б утром не вставало, когда бы не было меня
Re[3]: lock (this)
От: Кодт Россия  
Дата: 30.03.06 18:21
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>В Active Oberon семафоры изготавливают вручную:


Кстати говоря, статья — отличная иллюстрация механизма синхронизации "Conditional Variable".
Если этот механизм существует как примитив (на уровне языка {напр. Оберон} или библиотеки {напр. pthread}), то многое становится легче.

В виндоузе такого примитива нет, его приходится переизобретать. С++ники могут воспользоваться кроссплатформенными boost/thread или ACE.
Перекуём баги на фичи!
Re[3]: lock (this)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 30.03.06 23:31
Оценка:
Здравствуйте, Severn, Вы писали:

S>Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>> Будем переделывать d?

S>Зачем? d синхронизирует свои данные — по сути это некая дополнителная обработка между обращениями к a1 и a2.

[злой скип пожрал]

Здесь у тебя получается слишком много блокировок. Вернее, на каждый вызов MethForA1A2 происходит 3 захвата/освобождения объекта синхронизации.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: lock (this)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 30.03.06 23:43
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>>Будем переделывать d?


СГ>Да, переделаем...


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

[...]

СГ>...но это не особо сложно.

Недостаток здесь один — необходимость модификации класса d.

СГ>Сложнее в случае, когда надо блокировать нечто "по цепочке", т.е. "не отпускать одно не захватив следующее, а захватив следующее, отпускать предыдущее".

[...]
СГ>Здесь lock () {...} или BEGIN {EXCLUSIVE} ... END бессильны — нужны семафоры.
угу

СГ>В Active Oberon семафоры изготавливают вручную:


[...]

СГ>Более изощрённая задача — одновременно держать захваченным не 1-2 звена цепочки, а больше.


Ну вот. Собственно, этого я и ждал. А потом с помощью семафоров можно эмулировать всё многобразие объектов синхронизации...

Дело в том, что это опровергает необходимость так уж внимательно слушать певцов ООП. Какой смысл утверждать, что семафоры (сиречь, отчуждаемые объекты синхронизации) — это плохо, если на практике может оказаться, что без них — никуда?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: lock (this)
От: Severn Россия  
Дата: 31.03.06 01:38
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здесь у тебя получается слишком много блокировок. Вернее, на каждый вызов MethForA1A2 происходит 3 захвата/освобождения объекта синхронизации.


Точнее по одному захвату трех разных объектов. Что в этом плохого?
Если мы поместим MethForA2 внутри D, то количество блокировок уменьшится, но одновременно увеличится эффективный размер критических секций. Т.е. клент для MethForA2 будет ждать все время операции MethForA1A2, хотя ему до этого никакого дела нет.

По сути к этому:

СГ>Лочиться только на самом себе логически следует из объединения ООП и многопоточности:
СГ>1) Все данные инкапсулированы внутри объектов.
СГ>2) Доступ к любым данным осуществляется только с помощью методов объекта.
СГ>3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы (т.е такие методы, блоки кода в которых залочены на this).

стоит добавить пункт про распределение обязанностей. Если обязанности (данные/методы) распределены между объектами оптимальным образом, то в чем проблема в использовании lock(this)?
Re[10]: Решение задачи об очереди
От: ie Россия http://ziez.blogspot.com/
Дата: 31.03.06 02:26
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Здравствуйте, ie, Вы писали:


ie>> это должна быть коллекция "под конкретную задачу"


СГ>Естественно.


Так вот круг задач следовало определить в условии. Вот у меня бы рука не поднялась сделать такую реализацию для Queue общего типа (а ведь в условии не сказано обратного).

И еще вопрос. А если человек не будет использовать для синхронизации this, а создаст специальный объект для синхронизации. Это как-то повлияет на ваше решение при оценке данной задачи?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[11]: Задача о множестве
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 08:21
Оценка:
Здравствуйте, ie, Вы писали:

ie>Так вот круг задач следовало определить в условии. Вот у меня бы рука не поднялась сделать такую реализацию для Queue общего типа (а ведь в условии не сказано обратного).


Дык ведь она и не общего типа, а типа: EmployeeTest.IQueue.

ie>И еще вопрос. А если человек не будет использовать для синхронизации this, а создаст специальный объект для синхронизации. Это как-то повлияет на ваше решение при оценке данной задачи?


Вы такие вопросы задаёте... да если б кто решил хоть как-нибудь...

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

Задача о множестве

Напишите реализацию методов IsExist, Include, Exclude.

Время: 10 минут


namespace EmployeeTest
{
    public interface ISet
    {
        void Include (object element);
        void Exclude (object element);
        bool IsExist (object element);
    }

    public sealed class MySet: ISet
    {
        private sealed class List
        {
            public object head;
            public List tail;
            public List (object head, List tail)
            {
                this.head = head; this.tail = tail;
            }
        }

        private List list;

        public bool IsExist (object element)
        {
            // Помещен ли указанный элемент в это множество?
        }

        public void Include (object element)
        {
            // Если указанного элемента в этом множестве нет, поместить его.
        }

        public void Exclude (object element)
        {
            // Исключить указанный элемент из этого множества, если он в нем есть.
        }
    }
}

Re[4]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 08:38
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Какой смысл утверждать, что семафоры (сиречь, отчуждаемые объекты синхронизации) — это плохо...


Да ладно Вам... я утверждал немного другое. Плохо — это когда разрешено синхронизироваться на чём угодно, а не только на том, что специально для этого и было задумано, во что был вложен именно этот смысл. Например, в C# lock работает для всяких разных expression, а .Net-овский Monitor.Enter(object) работает для любых object, что может привести к трудно обнаруживаемым ошибкам, о которых уже сообщалось здесь
Автор: Oyster
Дата: 29.03.06
.
Re[4]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 08:48
Оценка:
Здравствуйте, Кодт, Вы писали:

К>В общем, как ни пытались отвертеться от опасных приёмов... сами же написали инструментарий для них.

.......
К>Почему сразу нельзя это сделать?

Да я не против такого инструментария, а против того, что в .Net вообще и в C# в частности разрешено лочится на ЛЮБОМ (чужом) объекте когда и где вздумается. Продолжение здесь
Автор: Сергей Губанов
Дата: 31.03.06
.
Re[4]: Решение задачи об очереди
От: stalcer Россия  
Дата: 31.03.06 09:01
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Сергей, предлагаю вам в качестве домашнего задания решить данную задачу вообще без объектов синхронизации. Максимум, InterlockedExchange, чтобы вам полегче было.


Имхо, Сергей прав. В данной постановке без аналога критической секции задачу решить нельзя.
Если убрать условие, что Dequeue должен ждать, то тогда да — можно. Точнее тогда будет рационально, так как очередь будет блокироваться каждый раз на очень маленькое время, и можно обоснованно применить аналог spin-lock'а из InterlockedIncrement/Decrement + Sleep(0).

Есть другие идеи?
Re[12]: Задача о множестве
От: ie Россия http://ziez.blogspot.com/
Дата: 31.03.06 09:26
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

ie>>Так вот круг задач следовало определить в условии. Вот у меня бы рука не поднялась сделать такую реализацию для Queue общего типа (а ведь в условии не сказано обратного).


СГ>Дык ведь она и не общего типа, а типа: EmployeeTest.IQueue.


И что? Мне ли вам рассказывать, что такое спецификация требований. Так вот тип EmployeeTest.IQueue никак спецификацией требований не является и никакие выводы о блокирующем Dequeue сделать нельзя. Ну да ладно, как я понял любое решение будет для вас приемлемым, что собственно и правильно.

ie>>И еще вопрос. А если человек не будет использовать для синхронизации this, а создаст специальный объект для синхронизации. Это как-то повлияет на ваше решение при оценке данной задачи?


СГ>Вы такие вопросы задаёте... да если б кто решил хоть как-нибудь...


СГ>По секреты скажу: ещё ни один испытуемый эту задачу решать не брался. Ознакомившись со всем списком предложенных задач, все кидаются решать задачу про множество, думая что она проще.


Для человека, писавшего на занятиях в универе добавление/удаление в/из списка, но не писавшего ни разу многопоточные приложения, эта задача действительно проще. К нам приходят на собеседование и многие даже не знают, что такое lock.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re[4]: Добавлю следующее...
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 09:47
Оценка:
Здравствуйте, Кодт, Вы писали:

СГ>>В Active Oberon семафоры изготавливают вручную:


К>Кстати говоря, статья — отличная иллюстрация механизма синхронизации "Conditional Variable".

К>Если этот механизм существует как примитив (на уровне языка {напр. Оберон} или библиотеки {напр. pthread}), то многое становится легче.

К>В виндоузе такого примитива нет, его приходится переизобретать. С++ники могут воспользоваться кроссплатформенными boost/thread или ACE.


Добавлю следующее.

Программистами придумано несколько (разных) способов синхронизации одновременно исполняющихся активностей, но, оказывается, их все можно друг через друга выразить. Возникает вопрос, какой способ синхронизации объявить более примитивным (базовым, элементарным, фундаментальным), чем другой? В языке Active Oberon фундаментальным обозван примитив AWAIT(condition) в связке с BEGIN{EXCLUSIVE} ... END блоком, который лочится на текущий объект (this) или модуль (в зависимости от того встретился ли он в процедуре-методе или в обычной процедуре-модуля). AWAIT(condition) выбран в качестве фундаментального, поскольку, не будь он фундаментальным, то скорее всего он был бы не очень эффективен. Например, самая неэффективная (просто тупая) реализация инструкции AWAIT(condition) есть пустой цикл

WHILE ~condition DO END;

останавливающийся только когда condition кто-то из другого потока присвоит значение TRUE.

В Windows/.Net инструкция AWAIT(condition) на уровне системы не реализована, поэтому сторонние, т.е. библиотечные реализации не очень эффективны как хотелось бы. Короче, программы на языке Active Oberon/Zonnon под Windows/.Net будут работать не так шустро как могли бы.

Владимир Лось работая в системе QNX написал библиотеку эмулирующую Active-Oberon-истые активные объекты на C++ с помощью примитивов синхронизации описанных в POSIX. На быстродействие AWAIT(condition) не жалуется. Говорит, что портировать эту C++ (POSIX) библиотеку под Windows не собирается, ибо смысл пропадёт — сильно медленнее работать будет. Вот его первая статья на эту тему: http://qnxclub.net/modules.php?name=Content&amp;pa=showpage&amp;pid=5

Владимир Лось. Активные объекты в С++.
Предлагается библиотека libao* . Сделана попытка реализации активных объектов в духе разработок ETHZ (Active Oberon, Zonnon). Даётся описание принципов построения активных объектов и краткое введение в предлагаемую библиотеку. Рекомендуется сначала прочитать статью...

Сейчас он "докручивает" там кое что, обещал в скором времени опубликовать ещё...

Ну, и тут нельзя не сказать про операционную систему Aos Bluebottle ( гы-гы, если кто ещё не знает) написанной на самом Active Oberon, а примитив AWAIT(condition) — реализован "прямо поверх голого железа", т.е. быстрее не бывает (ну если только аппаратно). Гуткнехт (создатель языков Active Oberon и Zonnon) во время осеннего турне (вместе с Виртом по России) обещал имплементировать язык Zonnon в Bluebottle где использование его станет сильно более эффективно нежели чем в .Net.
Re[5]: lock (this)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.03.06 12:39
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

ГВ>>Какой смысл утверждать, что семафоры (сиречь, отчуждаемые объекты синхронизации) — это плохо...


СГ>Да ладно Вам... я утверждал немного другое. Плохо — это когда разрешено синхронизироваться на чём угодно, а не только на том, что специально для этого и было задумано, во что был вложен именно этот смысл.


Не вижу противоречия. Семафоры как раз и задуманы для того, чтобы на них можно было синхронизироваться. Строго говоря — это вообще неделимая синхронизационная сущность. По сути, exclusive-секция, это не больше, чем управление семафором на входе/выходе и обход ожидающих conditinal expression.

СГ>Например, в C# lock работает для всяких разных expression, а .Net-овский Monitor.Enter(object) работает для любых object, что может привести к трудно обнаруживаемым ошибкам, о которых уже сообщалось здесь
Автор: Oyster
Дата: 29.03.06
.


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

Как раз для того, чтобы избежать ТОО в случае многопоточного програмирования можно (и нужно, на мой взгляд) выделить планирование захвата ресурсов в отдельные процедуры, возможно — взаимосинхронизированные (рассуждение с a1...d). В случае с "оберонским" подходом к реализации — выделить независимый объект, у которого все методы будут exclusive. В общем, такое разделение ничем не отличается от подхода, когда мы выделяем набор семафоров, а работу с ними помещаем в отдельные процедуры или классы. Есть только один недостаток — иной раз может потребоваться несколько таких объектов, например, по соображениям, связанным с наличием разных модулей и т.п. И вот тут-то будет не очень хорошо, поскольку в случае отчуждённых семафоров достаточно следовать политике захвата ресурсов, а в случае "оберон-подхода" придётся всякий раз модифицировать сам управляющий объект (LSP-violation? похоже, но не уверен).

Ну, скажем, для приведёного примера (он слегка надуман, ну ладно) в случае традиционного языка можно было бы поступить так:

Semaphore s_a1;
Semaphore s_a2;
Semaphore s_a1_a2;
SomeClass a1;
SomeClass a2;

// Далее, исполняем политику, в которой сказано, что при работе с a1 и a2 сначала следует залочить s_a1_a2
void func_a1a2()
{
  Guard g(s_a1_a2);
  Guard g1(s_a1);
  Guard g1(s_a2);
  // Много-много чего-то.
}

void func_a1()
{
  Guard g1(s_a1);
  // Здесь будет что-то про a1
}


Теперь, если нам захочется добавить какой-нибудь a3, с которым нужно работать вместе с a1 и a2, то можно поступить так:

Semaphore s_a3;
Semaphore s_other_a3;
SomeClass a3;

void func_a123()
{
  Guard g123(s_other_a3);
  Guard g3(s_a3);
  Guard g12(s_a1_a2); // Условно говоря, это - наследование имеющейся политики блокировок.
  Guard g1(s_a1);
  Guard g2(s_a2);
  // Интенсивно юзаем a1, a2, a3
}


И наконец, упростим себе задачу отслеживания политики — сделаем так, чтобы блокировка одного семафора гарантированно означала блокировку ряда других семафоров. Сформируем комплексные управляющие объекты:

class MultiSemaphore : public LockableObject
{
    Semaphore s_my_;
    /* Список адресов остальных семафоров */ others_sems_;
  public:
    MultiSemaphore(Semaphore *p1, ...)
    {
      /*читаем в цикле через va_arg*/ other_sems_.add(other_ptr);
    }
    //
    void Lock()
    {
      s_my_.Lock();
      /* Крутим цикл по списку others_sems_, от начала в конец */
      others_sems_[i]->Lock();
    }
    void Unlock()
    {
      // NB! Действуем строго в обратном порядке по отношению к Lock()!
      /* Крутим цикл по списку others_sems_, из конца в начало */
      others_sems_[i]->Unlock();
      s_my_.Unlock();
    }
}


Тогда задача отслеживания политики блокировок несколько упрощается:

Semaphore s_a1;
Semaphore s_a2;
MultiSemaphore s_a1_a2(&s_a1, &s_a2, 0); // 0 - терминатор списка

void func_a1_a2()
{
  Guard g(&s_a1_a2); // гарантируем себе, что блокировка проведена правильно.
}

void func_a1()
{
  Guard g(&a1);
  // ...
}


И когда добавляем a3 и s_a3:

Semaphore s_a3;
MultiSemaphore s_other_a3(&s_a3, &s_a1_a2, 0);

void func func_a123()
{
  Guard g(&s_other_a3);
  // Всё! В этой точке мы имеем корректно заблокированый контекст.
}


Дальше решение можно усложнить — внедрить, например, в MultiSemaphore алгоритмы предсказания блокировок и т.п. В общем — можно будет поиметь славный fun и приход.

При этом, что важно, нам не понадобилось менять уже имеющийся код, как это произойдёт в случае с "диспетчерским" объектом. Случаи патологической глупости и попыток захвата s_a1 поперёд s_a1_a2 я не рассматриваю. Также, впрочем, не буду апеллировать к возможности сделать семафор средствами самого Оберона, поскольку таким образом решение задачи на Обероне сводится к "классике".
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: lock (this)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.03.06 13:02
Оценка:
Здравствуйте, Severn, Вы писали:

ГВ>>Здесь у тебя получается слишком много блокировок. Вернее, на каждый вызов MethForA1A2 происходит 3 захвата/освобождения объекта синхронизации.

S>Точнее по одному захвату трех разных объектов. Что в этом плохого?

Да, верно. Притом захваты подчинённых объектов (a1 и a2) выполняются при каждом вызове их методов. Я, в общем-то, когда выдумывал пример, то предполагал, что захват агрегата a1+a2 нужен для какой-то, достаточно объёмной работы. Если нужно всего-то по одному разу вызвать методы a1 и a2, да ещё и с промежуточным храненим данных, то здесь, ИМХО, дополнительно блокировать весьт агрегат не нужно.

А если производится большой обмен данными (скажем — десяток вызовов a1 и столько же — a2), то можно здесь хорошо завалить производительность из-за постоянных lock/unlock на каждый вызов.

S>Если мы поместим MethForA2 внутри D, то количество блокировок уменьшится, но одновременно увеличится эффективный размер критических секций. Т.е. клент для MethForA2 будет ждать все время операции MethForA1A2, хотя ему до этого никакого дела нет.


Верно. Поэтому в таких методах нужно бороться с непредсказуемыми побочными эффектами. Например — не вызывать MessageBox. Насчёт увеличения длины критической секции — согласен, но такова плата за повышение общей производительности благодаря отказу от лишних блокировок/разблокировок.

S>По сути к этому:

S>

СГ>>Лочиться только на самом себе логически следует из объединения ООП и многопоточности:
СГ>>1) Все данные инкапсулированы внутри объектов.
СГ>>2) Доступ к любым данным осуществляется только с помощью методов объекта.
СГ>>3) Для синхронизированного (эксклюзивного) доступа к данным используются эксклюзивные методы (т.е такие методы, блоки кода в которых залочены на this).

S>стоит добавить пункт про распределение обязанностей. Если обязанности (данные/методы) распределены между объектами оптимальным образом, то в чем проблема в использовании lock(this)?

Да-да. Вопрос как раз в критериях "оптимальности".
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[6]: MultiSemaphore
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 13:27
Оценка: 9 (1)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>...поскольку таким образом решение задачи на Обероне сводится к "классике".


Не буду возражать. Я не против классики.

Кстати, вот мой вариант решения Вашей задачи про MultiSemaphore, но через Монитор.
Заранее извиняюсь, что не на Active Oberon, а на C#. Но на Active Oberon этот текст перепишется почти 1:1 заменяя:

lock (this) и Monitor.PulseAll(this) ---> BEGIN{EXCLUSIVE} ... END
while (this.IsBusy(indexies)) System.Threading.Monitor.Wait(this); ---> AWAIT(this.IsBusy(indexies))

ну, и лишаясь синтаксического сахара навроде params и foreach
namespace Test
{
  public sealed class MultiSemaphore
  {
    private readonly bool[] busyFlags;

    public MultiSemaphore (int count)
    {
      this.busyFlags = new bool[count];
    }

    private bool IsBusy (params int[] indexies)
    {
      foreach (int i in indexies) if (this.busyFlags[i]) return true;
      return false;
    }

    public void Enter (params int[] indexies)
    {
      lock (this)
      {
        while (this.IsBusy(indexies)) System.Threading.Monitor.Wait(this);
        foreach (int i in indexies) this.busyFlags[i] = true; // заняли
        System.Threading.Monitor.PulseAll(this);
      }
    }

    public void Exit (params int[] indexies)
    {
      lock (this)
      {
        foreach (int i in indexies) this.busyFlags[i] = false; // освободили
        System.Threading.Monitor.PulseAll(this);
      }
    }
  }
}

...я намеренно здесь не написал проверок индексов на принадлежность интервалу 0..this.busyFlags.Length-1, это конечно надо сделать в реальном коде, а этот код демонстрационный

Использование:
  MultiSemaphore sem = new MultiSemaphore(10000);

  // ...

  sem.Enter(26, 38, 17, 237, 266, 1001);
  // работа с объектами номер 26, 38, 17, 237, 266 и 1001
  sem.Exit(26, 38, 17, 237, 266, 1001);
Re[7]: MultiSemaphore
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 13:31
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>while (this.IsBusy(indexies)) System.Threading.Monitor.Wait(this); ---> AWAIT(this.IsBusy(indexies))


точнее, наоборот: AWAIT(~this.IsBusy(indexies))
Re[7]: MultiSemaphore
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.03.06 14:10
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

ГВ>>...поскольку таким образом решение задачи на Обероне сводится к "классике".

СГ>Не буду возражать. Я не против классики.

А как это вяжется с рассуждениями о недостатках традиционного подхода?

Разница в том, что залочится в C# можно на любом (чужом) объекте (быть может, на ровном месте неожиданно заработав deadlock), а в Active Oberon — только на самом себе (только на this).

Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[8]: Дыра
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 31.03.06 15:14
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>А как это вяжется с рассуждениями о недостатках традиционного подхода?

ГВ>

ГВ>Разница в том, что залочится в C# можно на любом (чужом) объекте (быть может, на ровном месте неожиданно заработав deadlock), а в Active Oberon — только на самом себе (только на this).


В моём примере MultiSemaphore разьве лок не на this делается?

На this.

Язык C# (в частности) и .Net (вообще) разрешают кому угодно другому напрямую залочится на объект MultiSemaphore ms следующим локом:

lock (ms)
{
...
}

не обращая внимания на (в обход) специально предусмотренного ms.Enter() и ms.Exit()?

Разрешает. И это есть дыра.

Мои претензии — к этой дыре.
Re[9]: Дыра
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.03.06 16:53
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

ГВ>>А как это вяжется с рассуждениями о недостатках традиционного подхода?

СГ>В моём примере MultiSemaphore разьве лок не на this делается?
СГ>На this.

Угу. Но наличие методов Enter/Exit как раз и лишает блокировку локальности.

СГ>Язык C# (в частности) и .Net (вообще) разрешают кому угодно другому напрямую залочится на объект MultiSemaphore ms следующим локом:


СГ>lock (ms)

СГ>{
СГ> ...
СГ>}

СГ>не обращая внимания на (в обход) специально предусмотренного ms.Enter() и ms.Exit()?

Хмм... Цитата из MSDN:

Monitor.Enter
[...]
Invoking this member is identical to using the C# lock statement.


Я чего-то не понимаю... Или претензия к тому, что один поток может залочиться на семафор "снаружи", а другой в это время позовёт его методы не выполнив lock(semaphore)?

СГ>Разрешает. И это есть дыра.

СГ>Мои претензии — к этой дыре.

Так создавая объект "Семафор" на Обероне мы и создаём ту же самую "дыру". Даже не в профиль. То есть, сводим ряд задач к привычному "дырявому" базису. Семафор тоже может "залочить" кто угодно — для того он и создаётся, собственно.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[9]: А нет, стоп
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.03.06 17:10
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

Поторопился с ответом, ввело в заблуждение совпадение названий Monitor.Enter и MultiSemaphore.Enter. Действительно, не следует путать lock(ms) и ms.Enter/ms.Exit. В общем — да, можно считать подобное "дырой", хотя опять-таки, палка сия о двух концах. Ну так здесь дыра не в "нелокальности" блокировок, а в том, что объектом синхронизации может выступать всё что угодно, а не только специально предназначенные для этого сущности (семафоры, мьютексы, критические секции и т.п.).

Тогда, пожалуй, что соглашусь — риск налететь на deadlock при таком подходе повышается. Но, повторюсь, дело здесь не в "нелокальности", а в том, что, фактически, у нас количество семафоров равно количеству объектов (+ N * количество_объектов_value-типов за счёт боксинга).
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: lock (this)
От: alexeiz  
Дата: 01.04.06 06:27
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> sync block используется не только для блокировки но и например для дефолтного GetHashCode итд


Сдаётся мне, что в версии 2 это уже не так. Хотя, нужно проверить по коду SSCLI 2.0.
Re[10]: Дыра
От: Кодт Россия  
Дата: 02.04.06 11:57
Оценка: +1
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Так создавая объект "Семафор" на Обероне мы и создаём ту же самую "дыру". Даже не в профиль. То есть, сводим ряд задач к привычному "дырявому" базису. Семафор тоже может "залочить" кто угодно — для того он и создаётся, собственно.


Тут есть маленький штрих. lock() позволяет извне залочить любой объект (ну, ассоциированный с этим объектом мьютекс, неважно). А если мьютекс является внутренней принадлежностью объекта (на уровне языка, как в Обероне, или на уровне библиотек, как в большинстве других языков), то он и только он решает, кому и как позволено лочить. Инкапсуляция, понимаш.

class Something
{
private:
  mutable mutex guard_; // чтобы сделать Something монитором, нам нужно владеть мьютексом...
public:
  void foo()
  {
    mutex::scoped_lock exclusive(guard_); // ... и пользоваться им
    .....
  }

  // если любишь в жизни риск, форматируй жёсткий диск
  mutex& guard() const { return guard_; }
  void lock() const { guard_.lock(); }
  void unlock() const { guard_.unlock(); }
  // никто не заставляет отдавать ручки наружу - только добрая или злая воля автора
}


Если мы на Обероне создали объект "мьютекс" и пользуемся им — то пользователь должен быть очень настойчивым и глупым, чтобы 1) напихать эти мьютексы во все структуры и 2) лочить их направо и налево.
Перекуём баги на фичи!
Re[11]: Дыра
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 02.04.06 18:47
Оценка: +1
Здравствуйте, Кодт, Вы писали:

ГВ>>Так создавая объект "Семафор" на Обероне мы и создаём ту же самую "дыру". Даже не в профиль. То есть, сводим ряд задач к привычному "дырявому" базису. Семафор тоже может "залочить" кто угодно — для того он и создаётся, собственно.


К>Тут есть маленький штрих. lock() позволяет извне залочить любой объект (ну, ассоциированный с этим объектом мьютекс, неважно).


Угу. В общем, я с этим согласен
Автор: Геннадий Васильев
Дата: 31.03.06
и вот, почему:

Тогда, пожалуй, что соглашусь — риск налететь на deadlock при таком подходе повышается. Но, повторюсь, дело здесь не в "нелокальности", а в том, что, фактически, у нас количество семафоров равно количеству объектов (+ N * количество_объектов_value-типов за счёт боксинга).


В общем, мои позиции таковы:

1. Защита от deadlock-ов начинается с планирования синхронизаций и построения графа блокировок.
2. Метод реализации должен выбираться в соответствии с задачей и имеющимися языковыми средствами.
3. Реализация не должна разрушать план синхронизации.

Почему я согласен с СГ в той части, что в .Net есть "дыра"? Потому что очень легко нарушить граф синхронизации — зацепив любой объект. То есть, нужно вводить ограничения на использование определённых конструкций языка. В принципе, ничего страшного тут нет — решаемо.

Почему я не согласен с СГ в той части, что лучший способ управления — самоблокировка? Потому что иначе не было бы нужды делать семафоры в Обероне. Я не сомневаюсь, что немалую часть задач можно решить посредством EXCLUSIVE/AWAIT, просто где-то таких exclusive нужно два (захват/отпускание). С другой стороны, не всегда синхронизируемые процессы могут принадлежать одному объекту или классу.

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

Вот так или примерно так.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[7]: MultiSemaphore
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 03.04.06 14:00
Оценка:
СГ>Заранее извиняюсь, что не на Active Oberon, а на C#.

На Zonnon:
object MultiSemaphore;

  var busy: array 1000 of boolean;

  procedure IsBusy (s: array of integer): boolean;
    var i: integer;
  begin
    for i := 0 to len(s)-1 do
      if busy[s[i]] then return true end
    end;
    return false
  end IsBusy;

  procedure SetBusy (s: array of integer; val: boolean);
    var i: integer;
  begin
    for i := 0 to len(s)-1 do busy[s[i]] := val end
  end SetBusy;

  procedure {public} Enter (s: array of integer);
  begin {locked}
    await ~IsBusy(s);
    SetBusy(s, true)
  end Enter;

  procedure {public} Exit (s: array of integer);
  begin {locked}
    SetBusy(s, false)
  end Exit;

end MultiSemaphore.
Re[8]: lock (this)
От: SteMage Россия  
Дата: 04.04.06 08:17
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, SteMage, Вы писали:


SM>>Разумное самоограничение ВСЕХ программистов в проекте и все ок. Вот только иногда проще заставить программистов работать со средством разработки принципиально запрещающем что-то делать, нежели добится разумного самоограничения.


Д>В данном случае сделать глобальный поиск по исходникам и раздать звиздюли по его результатам — совершенно несложная задача


А если код протестирован временем и его нельзя трогать? Знаете менеджеры иногда готовы увольнять программистов за рефакторинг. Да как будем боротся с наведенными эффектами? А если так пишет единственный разработчик разбирающийся в проекте? Как то вы предлагаете простое организационное решение, которое в жизни очень часто не работает.

SM>>Хотя бесусловно обсуждаемый момент может быть не достаточно важной причиной для смены средства разработки и т.д.


Д>скорее — не может быть достаточно важной причиной. Тем более что надо не только менять средство разработки, но еще и переписывать весь код.


Может при прочих равных. Вы ведь не против типизации? Или все таки против?
Re[9]: lock (this)
От: Дарней Россия  
Дата: 04.04.06 08:53
Оценка:
Здравствуйте, SteMage, Вы писали:

SM>А если код протестирован временем и его нельзя трогать? Знаете менеджеры иногда готовы увольнять программистов за рефакторинг.


Если катастрофически нет времени в данный момент — да, они правы. А в остальных случаях увольнять надо таких менеджеров.

SM>Да как будем боротся с наведенными эффектами?


Какие еще наведенные эффекты могут быть от замены lock(this) на lock(syncObject)?

SM>А если так пишет единственный разработчик разбирающийся в проекте?


Уволить всех, влючая этого разработчика. Или валить к чертовой бабушке из такого проекта. Или оба варианта вместе.

SM>Как то вы предлагаете простое организационное решение, которое в жизни очень часто не работает.


Вот это конкретное решение, в этом конкретном случае? Ты проверял?

Д>>скорее — не может быть достаточно важной причиной. Тем более что надо не только менять средство разработки, но еще и переписывать весь код.


SM>Может при прочих равных. Вы ведь не против типизации? Или все таки против?


А что — типизация? Почти в любом языке есть конструкции, которые не имеют прямого аналога в другом языке, и вообще реализуются с трудом. К тому же язык — это не только язык, но еще и платформа, на которой он работает. Причем платформа — это не только и не столько ось, сколько набор библиотек и инструментов, созданных для этого языка.
Ты что, серьезно думаешь, что типизация поможет тебе портировать прогу с (к примеру) C# на оберон? Переписать полностью, и скорее всего перепроектировать — единственный возможный вариант. То есть, на самом деле, невозможный.
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[10]: lock (this)
От: SteMage Россия  
Дата: 04.04.06 10:50
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, SteMage, Вы писали:


Д>Какие еще наведенные эффекты могут быть от замены lock(this) на lock(syncObject)?


Чужой исходный код или отдали что-то на аутсорс, а исходников нет, а делать надо.

Д>Вот это конкретное решение, в этом конкретном случае? Ты проверял?


Вот конкретное решение я много раз проверял в жизни. Оно не работает во многих случаях. Для того чтобы оно работало должен быть довольно жестко организованный процесс разработки, а это много чего значит. Далеко не всегда это так, ваш совет увольнятся с работы (и идти например на в два раза меньшую зарплату) больше похож на утопию. Вы ВЕРИТЕ в организационные методы. Я принципиально в них НЕ ВЕРЮ.

Д>>>скорее — не может быть достаточно важной причиной. Тем более что надо не только менять средство разработки, но еще и переписывать весь код.


SM>>Может при прочих равных. Вы ведь не против типизации? Или все таки против?


А где вы видели утверждение о том, что Я предлагаю все переписать на Обероне? Например почему не начать новый проект на Обероне, если он содержит необходимые нам библиотеки? Я лишь утверждаю, что при прочих равных это может быть решаюшим доводом в пользу выбора платформы. Кто сказал, что издержки на обучения будут выше издержек на правку багов или наладки нормального процесса разработки?

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

Да кстати я так и не услышал ответа на свой вопрос по поводу типизации.
Re[11]: lock (this)
От: Дарней Россия  
Дата: 05.04.06 01:23
Оценка:
Здравствуйте, SteMage, Вы писали:

Д>>Какие еще наведенные эффекты могут быть от замены lock(this) на lock(syncObject)?


SM>Чужой исходный код или отдали что-то на аутсорс, а исходников нет, а делать надо.


А что вообще ты собрался делать, если нет исходников?
И все-таки, какие вообще наведенные эффекты могут быть от такой замены в принципе?

Д>>Вот это конкретное решение, в этом конкретном случае? Ты проверял?


SM>Вот конкретное решение я много раз проверял в жизни. Оно не работает во многих случаях. Для того чтобы оно работало должен быть довольно жестко организованный процесс разработки, а это много чего значит. Далеко не всегда это так, ваш совет увольнятся с работы (и идти например на в два раза меньшую зарплату) больше похож на утопию. Вы ВЕРИТЕ в организационные методы. Я принципиально в них НЕ ВЕРЮ.


Я не верю в организационные методы, я просто их иногда использую. А еще я не верю в незыблемые принципы, потому что это уже из области религии. Одни и те же методы могут и работать, и не работать, в зависимости от обстоятельств.
Какие проблемы могут быть вот в данном конкретном случае? И вообще, почему обязательно в два раза меньшую зарплату? У меня обычно бывает наоборот

SM>А где вы видели утверждение о том, что Я предлагаю все переписать на Обероне? Например почему не начать новый проект на Обероне, если он содержит необходимые нам библиотеки? Я лишь утверждаю, что при прочих равных это может быть решаюшим доводом в пользу выбора платформы.


"прочих равных" здесь нет и быть не может. Единственной причиной для выбора оберона могут быть религиозные соображения, потому что по всем реальным характеристикам он сливает другим технологиям. Для embedded есть Symbian. Для параллельных систем — Erlang. И так далее.

SM>Сравнение с типизацией не случайно. Типизация позволяет избежать ряда ошибок. Обсуждаемая особенность позволяет избежать ряда ошибок, при этом не создавая дополнительных проблем.


А какой "ряд ошибок" может быть по причинам, которые мы сейчас рассматриваем?

SM>Да кстати я так и не услышал ответа на свой вопрос по поводу типизации.


Ты хочешь об этом поговорить? Если действительно очень хочешь, то я отвечу — сильная статическая типизация рулит в большинстве случаев.
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[12]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 05.04.06 08:25
Оценка: +1
Здравствуйте, Дарней, Вы писали:

Д>Единственной причиной для выбора оберона могут быть религиозные соображения, потому что по всем реальным характеристикам он сливает другим технологиям.


Извините, конечно, что вмешиваюсь в ваш спор, но, вроде, Ваш оппонент ничего про Oberon и не утверждал. Это во-первых, так что Ваш выпад против Oberon неуместен и непонятен. Во-вторых, коль скоро этот выпад Вами всё-таки был сделан, то со своей стороны, замечу, что Вы сказали неправду. По реальным характеристикам, например, Blackbox находится где-то на уровне технологий .Net & Java. На разных оберонах написан ряд операционных систем, в том числе операционных систем реального времени, в том числе для встраиваемых аппаратных систем. Кроме того, ведущие академические проекты осуществлялись и осуществляются именно на оберонах. Обероны успешно используются и в ряде коммерческих организаций. А на Modula (предшественнике Oberon) программируются космические спутники.
Re[13]: lock (this)
От: Дарней Россия  
Дата: 05.04.06 09:52
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Извините, конечно, что вмешиваюсь в ваш спор, но, вроде, Ваш оппонент ничего про Oberon и не утверждал. Это во-первых, так что Ваш выпад против Oberon неуместен и непонятен.


Поскольку в данной ветке мы обсуждали фичу именно оберона, то меня очень удивляет твое утверждение, что мое заявление о нем здесь неуместно.

СГ> Во-вторых, коль скоро этот выпад Вами всё-таки был сделан, то со своей стороны, замечу, что Вы сказали неправду. По реальным характеристикам, например, Blackbox находится где-то на уровне технологий .Net & Java.


Список этих реальных характеристик — в студию! Желательно в виде таблицы с плюсиками и минусиками. Только реальных фич, а не типа "в комментарии можно вставлять картинки"

СГ>На разных оберонах написан ряд операционных систем, в том числе операционных систем реального времени, в том числе для встраиваемых аппаратных систем. Кроме того, ведущие академические проекты осуществлялись и осуществляются именно на оберонах. Обероны успешно используются и в ряде коммерческих организаций. А на Modula (предшественнике Oberon) программируются космические спутники.


да, как же много зависит от правильной постановки высказывания
Мне даже лень снова посылать тебя в googlewars... может быть, проще согласиться? (в глубоком раздумье)
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[6]: lock (this)
От: AVC Россия  
Дата: 05.04.06 11:43
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Ну, скажем так. К труднообнаружимым ошибкам (ТОО) обычно приводит хаотичный процесс разработки. Сами по себе особености того или иного языка влияют на возникновение ошибок весьма косвенно.


Думается, между языком и процессом разработки есть связь.
IMHO, язык создается в расчете на определенный характер процесса разработки, и именно поэтому в Си так много "лазеек" (loopholes), а в Обероне — мало.

Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.

Хоар
Re[12]: lock (this)
От: SteMage Россия  
Дата: 06.04.06 09:29
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, SteMage, Вы писали:


Д>>>Какие еще наведенные эффекты могут быть от замены lock(this) на lock(syncObject)?


SM>>Чужой исходный код или отдали что-то на аутсорс, а исходников нет, а делать надо.


Д>А что вообще ты собрался делать, если нет исходников?

Д>И все-таки, какие вообще наведенные эффекты могут быть от такой замены в принципе?

Скажите а сборки в .NET уже отменили? Рассмотрим ситуацию у нас есть пакет основной, который делает другая организация. И есть два пакета, которые делаются на его основе. Мы делаем один пакет, а другая фирма делает другой пакет. Теперь рассмотрим ситуацию, что у нас что-то не работает. Количество возможных причин почему у нас не работает, при использовании активных объектов падает или увеличивается?

Я полагаю, что падает, поскольку исключена потенциально опасная конструкция. Я не прав?

SM>>Вот конкретное решение я много раз проверял в жизни. Оно не работает во многих случаях. Для того чтобы оно работало должен быть довольно жестко организованный процесс разработки, а это много чего значит. Далеко не всегда это так, ваш совет увольнятся с работы (и идти например на в два раза меньшую зарплату) больше похож на утопию. Вы ВЕРИТЕ в организационные методы. Я принципиально в них НЕ ВЕРЮ.



Д>Я не верю в организационные методы, я просто их иногда использую. А еще я не верю в незыблемые принципы, потому что это уже из области религии. Одни и те же методы могут и работать, и не работать, в зависимости от обстоятельств.

Д>Какие проблемы могут быть вот в данном конкретном случае? И вообще, почему обязательно в два раза меньшую зарплату? У меня обычно бывает наоборот

К сожалению то, какие организационные методы использовать обычно решают не программисты, надеюсь не надо объяснять как сложно перестраивать уже существующий процесс разработки? У вас дети жена есть? Это пока вы свободный человек и у вас есть достаточно большие сбережения вы можете себе позволить менять работу тогда, когда вам удобно. А вот в остальных случаях все не так хорошо. И рецепт валить очень часто не работает.

SM>>А где вы видели утверждение о том, что Я предлагаю все переписать на Обероне? Например почему не начать новый проект на Обероне, если он содержит необходимые нам библиотеки? Я лишь утверждаю, что при прочих равных это может быть решаюшим доводом в пользу выбора платформы.


Д>"прочих равных" здесь нет и быть не может. Единственной причиной для выбора оберона могут быть религиозные соображения, потому что по всем реальным характеристикам он сливает другим технологиям. Для embedded есть Symbian. Для параллельных систем — Erlang. И так далее.


Ну походу случай клинический. Скажите мы собираемся выпустить новый процессор что делать? И сколько это стоит? Неужели вы не видите какя выстраивается пирамида с Java и .Net? И где в этой пирамиде вершина?

Тему пирамиды я готов с вами обсудить.

А вот если вдруг IBM возьмет и напишет систему использующую активные объекты, что тогда? Не я понимаю, что это очень очень мало вероятно, но все таки.

Д>Ты хочешь об этом поговорить? Если действительно очень хочешь, то я отвечу — сильная статическая типизация рулит в большинстве случаев.


Нет я проверяю вменяемость того с кем разговариваю. Если человек не признает типизацию, то ИМХО он не вменяемый.
Re[13]: lock (this)
От: Cyberax Марс  
Дата: 06.04.06 09:40
Оценка:
SteMage wrote:
> А вот если вдруг IBM возьмет и напишет систему использующую активные
> объекты, что тогда? Не я понимаю, что это очень очень мало вероятно, но
> все таки.
Да ничерта не будет. Немного другой набор примитивов синхронизации
ничего не меняет.

Вот в POSIX есть condition'ы, а в Win32 их нет. И что, мир от этого рушится?
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[13]: lock (this)
От: Дарней Россия  
Дата: 06.04.06 10:24
Оценка:
Здравствуйте, SteMage, Вы писали:

SM>Скажите а сборки в .NET уже отменили? Рассмотрим ситуацию у нас есть пакет основной, который делает другая организация. И есть два пакета, которые делаются на его основе. Мы делаем один пакет, а другая фирма делает другой пакет. Теперь рассмотрим ситуацию, что у нас что-то не работает. Количество возможных причин почему у нас не работает, при использовании активных объектов падает или увеличивается?


SM>Я полагаю, что падает, поскольку исключена потенциально опасная конструкция. Я не прав?


я вообще не понимаю, что ты хочешь сказать. Потенциально опасная конструкция исключена у кого — "у нас" или "у них"? Это — во первых.
А во вторых — насколько опасна эта конструкция? Тебя послушать, так по сравнению с этим даже проход по памяти меркнет. А на самом деле, нужно иметь очень специфический генокод, чтобы напороться на такую проблему.

SM>К сожалению то, какие организационные методы использовать обычно решают не программисты, надеюсь не надо объяснять как сложно перестраивать уже существующий процесс разработки?


Руководитель группы не может решать, как ему вести работу в своей группе? Ну тогда из такой фирмы надо бежать, как от огня.

SM>У вас дети жена есть? Это пока вы свободный человек и у вас есть достаточно большие сбережения вы можете себе позволить менять работу тогда, когда вам удобно. А вот в остальных случаях все не так хорошо. И рецепт валить очень часто не работает.


А переход на оберон эту проблему должен решить, я так понимаю?

SM>Ну походу случай клинический. Скажите мы собираемся выпустить новый процессор что делать? И сколько это стоит? Неужели вы не видите какя выстраивается пирамида с Java и .Net? И где в этой пирамиде вершина?


ничего не понимаю. Какая еще прирамида?

SM>Тему пирамиды я готов с вами обсудить.


главное, не предлагай купить акции АО "МММ"

SM>А вот если вдруг IBM возьмет и напишет систему использующую активные объекты, что тогда? Не я понимаю, что это очень очень мало вероятно, но все таки.


Ericsson уже написал. Причем давно. Только вот обероном там даже и не пахнет. Там функциональщиной пахнет, а это уже совсем другой оборот

SM>Нет я проверяю вменяемость того с кем разговариваю. Если человек не признает типизацию, то ИМХО он не вменяемый.


странные у тебя способы проверки.
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[14]: lock (this)
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 07.04.06 09:20
Оценка: +1
Здравствуйте, Дарней, Вы писали:

Д>Список этих реальных характеристик — в студию! Желательно в виде таблицы с плюсиками и минусиками. Только реальных фич, а не типа "в комментарии можно вставлять картинки"


Не в фичах сила!
Смотри презентации: http://cern.ch/oberon.day/programme.html
Re[15]: lock (this)
От: Дарней Россия  
Дата: 07.04.06 09:35
Оценка: +1 :)
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Не в фичах сила!

СГ>Смотри презентации: http://cern.ch/oberon.day/programme.html

видимо, сила в пиаре?
... << RSDN@Home 1.1.4 stable rev. 510>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.