Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Вниз

Был, сегодня, на собеседовании   Найти похожие ветки 

 
ikivio   (2004-04-23 00:01) [0]

Если вы создаете свой класс, то, как не допустить создание
Его второго экземпляра ?
( без глобальной переменной, и перехода типа: if … then Create )


 
ikivio   (2004-04-23 00:12) [1]

Забыл добавить фразу: Засыпался на вопросе:


 
VMcL ©   (2004-04-23 00:12) [2]

CreateMutex + вместо if Condition then DoSome:
While Condition do
begin
 DoSome;
 Break;
end;


 
ikivio   (2004-04-23 00:16) [3]

На мою первую фразу: митех - ответ: в пределах одного
exe file


 
Suntechnic ©   (2004-04-23 00:33) [4]

Singleton pattern эта штука называется. Любимейший вопрос на любом интервью по любому из языков программирования.


 
ikivio   (2004-04-23 00:37) [5]

Да..., и еще:
Когда идет попытка создания,
надо не создать новый, а перейти на уже созданный.
>Suntechnic
можно подробнее ?


 
Fantasist ©   (2004-04-23 00:44) [6]


> Singleton pattern эта штука называется.


 Называться-то она может и называеться, однако к реализации в ТАКИХ условиях она не приближает. Обычно все-таки учавствует некая глобальная переменная, для хранения созданного объекта.


 
Suntechnic ©   (2004-04-23 00:53) [7]

>ikivio
Подробности здесь:
http://www.google.com/search?hl=en&ie=UTF-8&oe=UTF-8&q=Singleton+pattern

Или поищи на форуме, здесь эта тема не раз обсуждалась.

>Fantasist ©
Я это к тому, что идя на интервью надо быть готовым к таким вопросам. Иногда вопрос может просто звучать Singleton pattern in .... (С++, Delphi, С# and etc.) и точка.

Честно говоря у человека не способного показать имплементацию этого паттерна очень мало шансов получить работу.


 
ikivio   (2004-04-23 00:56) [8]

>Fantasist
И, как можно ответить на этот вопрос ?


 
ikivio   (2004-04-23 01:06) [9]

>Suntechnic
Согласен.
 Но, не на все у тебя сразу готовы ответы.
 Если, ты этим не занимался, то можно слазить в Help и т.д.
 Т. е. дай - время - разберусь.


 
Fantasist ©   (2004-04-23 02:52) [10]


> Честно говоря у человека не способного показать имплементацию
> этого паттерна очень мало шансов получить работу.


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


> И, как можно ответить на этот вопрос ?


 Возможно имеется ввиду константа в функции:


function TMObject.A:pointer;
const
 _global:pointer = nil;
begin
end;


 Вроде как по смыслу не глобальная переменная, а функцию может выполнять ту же.
 А далее, как тут уже обсуждалось - перекрыть NewInstance и FreeInstance.


 
SPeller ©   (2004-04-23 03:30) [11]

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


 
Suntechnic ©   (2004-04-23 04:38) [12]

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

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

На С++ тоже этот патерн так имплементировать, что только уборщиком на работу и возьмут. Одно дело знать что это вообще такое, а другое как это имплементировать.


 
шлшмшщ   (2004-04-23 08:00) [13]

>Suntechnic
Спасибо. Ссылка помогла.
Как говориться: знал бы - соломки подстелил


 
LaidBack   (2004-04-23 09:44) [14]

Ну и нафига такие извращения нужны в реальной жизни программеру? Я считаю основным достоинством программера - умение самомтоятельно находить нужное решение задачи, с помощью головы, help"a и internet. И если в данный момент я не знаю ответа на этот вопрос нельзя сказать, что я ламер, просто это мне нафиг не нужно было. Понадобится - узнаю :)


 
Игорь Шевченко ©   (2004-04-23 10:09) [15]


> Ну и нафига такие извращения нужны в реальной жизни программеру?
> Я считаю основным достоинством программера - умение самомтоятельно
> находить нужное решение задачи, с помощью головы


Ты сказал. (с) Евангелие

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


 
Kerk ©   (2004-04-23 10:16) [16]


> Игорь Шевченко ©   (23.04.04 10:09) [15]
> Насколько я понял, на собеседовании и предложили найти решение
> с помощью головы.

Так на собеседовании не разрешают на форуме спрашивать! :)


 
Леприкон ©   (2004-04-23 10:31) [17]

Если я не в тему, то извините меня грешного.
А гуманно ли выдавать при собеседовании белый лист бумаги и ручку. Мол, вот задание, пиши. А если я забыл какой либо компонент с закладки QReport (или вообще забыл название закладки) ибо им редко пользуюсь. И уж тем более не знаю всех его методов и свойств. Что, мои знания в Delphi равны 0? Если уж писать, то в редакторе кода. Code Insight ведь для чего то нужен?


 
mrcat ©   (2004-04-23 10:34) [18]

>А если я забыл какой либо компонент с закладки QReport
>И уж тем более не знаю всех его методов и свойств
А что, такое требуют при собеседовании ? :)


 
Тимохов ©   (2004-04-23 10:41) [19]

если бы с глобальной переменной, то я бы через newinstance сделал
типа такого

var
  kO: TObj;

class function TObj.NewInstance: TObject;
begin
  if kO <> nil then
     result := kO
  else
  begin
     result := Inheried;
     kO := result;
  end;
end;


Уточнил бы еще - нужно ли это все потокобезопасно или все в рамках одного потока.
Не забыл бы, конечно, про freeinstance.

Без гл. переменной - не знаю.


 
Леприкон ©   (2004-04-23 10:43) [20]


> mrcat ©   (23.04.04 10:34) [18]


Да, личный опыт. Просили сделать небольшой отчёт в QReport. Ограничеие по времени 10 мин. Я не долго думая поставил рядом жирный прочерк.


 
Rule ©   (2004-04-23 10:44) [21]

Kerk ©   (23.04.04 10:16) [16]

Тогда получилось бы что на собеседование не он проходит а весь форму, и я думаю мы бы прорвались :), хоть к самому Билу Гейтсу :)


 
Тимохов ©   (2004-04-23 10:45) [22]


>  хоть к самому Билу Гейтсу :)

с паскалем, как  же...


 
Игорь Шевченко ©   (2004-04-23 11:06) [23]

Тимохов ©   (23.04.04 10:41)

Представь, что ты вызвал два раза конструктор такого объекта, результат присвоил двум разным переменным. Один раз вызвал ПерваяПеременная.Free. На что будет указывать вторая переменная ?


 
Тимохов ©   (2004-04-23 11:12) [24]


> Игорь Шевченко ©   (23.04.04 11:06) [23]

К чему вопрос?
От автора поста требовали написать класс не позволяющий создавать второй экземпляр.
Вроде задача выполнена.
Можно конечно в newinstance генерить exception если создается второй экземпляр, но это уже зависит от задачи - не пущать или подставлять первый вариант.

Вы приводите дальнейшее условие задачи?


 
Dmitriy O. ©   (2004-04-23 11:41) [25]


> Леприкон ©   (23.04.04 10:43)
"Программер можешь ты не быть но Qreport ты знать обязан"
(с) Мое


 
Игорь Шевченко ©   (2004-04-23 11:50) [26]

Тимохов ©   (23.04.04 11:12)

И все-таки, на что будет указывать вторая переменная ? :)


 
Паниковский ©   (2004-04-23 11:58) [27]

Игорь Шевченко
на туда на что угодно
ну и ?


 
Тимохов ©   (2004-04-23 12:03) [28]


> И все-таки, на что будет указывать вторая переменная ? :)

чую, что подхов какой-то :))
но вроде, на что и указывала :)
только объекта по этому адресу уже не будет.


 
Игорь Шевченко ©   (2004-04-23 13:05) [29]

Тимохов ©   (23.04.04 12:03)

А написать примерчик, и проверить ? :) 5 минут ведь потребуется.

> только объекта по этому адресу уже не будет.


И что получится при попытке обращения к объекту по указателю во воторой переменной ? :)


 
ikivo   (2004-04-23 13:21) [30]

Только сейчас вошел в интернет.
Всем спасибо !
>Тимохов
>Вы приводите дальнейшее условие задачи?
При создании нового он должен не создасться,
а перевести "стрелки" на уже созданный.


 
Layner ©   (2004-04-23 13:24) [31]

Это на какую работу искали спеца, если не секрет, в каком городе, и что надо было делать?


 
ikivio   (2004-04-23 13:37) [32]

>Layner ©   (23.04.04 13:24) [31]
>Это на какую работу искали спеца, если не секрет, в каком >городе, и что надо было делать?
Petersbug
программист, "знающий Delphi"
>делать
переделывать чужой код


 
Layner ©   (2004-04-23 13:48) [33]

Уууу ... переделывать ... не, ищи лучше работу в другом месте. В Питере спрос вроде высокий на IT специалистов...
программист, "знающий Delphi"
Если про среду разработаки, то может версию указали? А про ООП зачем спрашивают? Нафиг такая работа, одним словом, там наверняка ещё стеклянная стена, и все мониторы видно начальником, который сидит за стекл. стеной и следит 8 часов, чем занимаются сотрудники...


 
ikivio   (2004-04-23 13:58) [34]

>Layner
>ищи лучше работу в другом месте
$1300 - убеждает
Да я не для разборок создал веку.
Просто обидно.
Ну, не знаю - "дай - время - разберусь."


 
Тимохов ©   (2004-04-23 14:04) [35]


> Игорь Шевченко ©   (23.04.04 13:05) [29]


type
  TClassX = class
     public procedure Change(); virtual; // чтобы не был статическим
     public class function NewInstance: TObject; override;
  end;

procedure TClassX.Change();
begin
  ShowMessage("hi");
end;

var
  kObjectX: TClassX = nil;

class function TClassX.NewInstance: TObject;
begin
  if kObjectX = nil then kObjectX := TClassX(inherited NewInstance);
  Result := kObjectX;
end;

procedure TForm1.Button19Click(Sender: TObject);
var
  kO1, kO2: TClassX;
begin
  kO1 := TClassX.Create();
  kO2 := TClassX.Create();
  kO1.Free();
  kO2.Change(); // <- av
end;


av есть, как и следовало ожидать.
как этого избежать, т.е. не давать уничтожать объект, если на него кто-то смотрит?
пока не знаю - надо подумать.
в чем вопрос то?


 
Locker   (2004-04-23 14:21) [36]

constructor TMyClass.Create;
const
 Created: boolean = false;
begin
 if (Created) then raise Exception.Create("Экземпляр класса уже создан");
 ...
 boolean((@Created)^) := true;
end;


 
Тимохов ©   (2004-04-23 14:23) [37]


> Locker   (23.04.04 14:21) [36]

вроде по уточненному уловию надо не отлуп дать а тихо подменить старым значением.


 
Игорь Шевченко ©   (2004-04-23 14:26) [38]

unit HSSingleton;

interface

type
 THSSingleton = class
 private
   FInstanceCount: Integer;
 public
   class function NewInstance: TObject; override;
   procedure FreeInstance; override;
 end;

implementation
uses
 Windows;

{ THSSingleton }

var
 Instance: THSSingleton;
 CritSect: RTL_CRITICAL_SECTION;

procedure THSSingleton.FreeInstance;
begin
 EnterCriticalSection(CritSect);
 try
   Dec(FInstanceCount);
   if FInstanceCount = 0 then begin
     inherited;
     Instance := nil;
   end;
 finally
   LeaveCriticalSection(CritSect);
 end;
end;

class function THSSingleton.NewInstance: TObject;
begin
 EnterCriticalSection(CritSect);
 try
   if not Assigned(Instance) then
     Instance := THSSingleton(inherited NewInstance);
   Result := Instance;
   Inc(Instance.FInstanceCount);
 finally
   LeaveCriticalSection(CritSect);
 end;
end;

initialization
 InitializeCriticalSection(CritSect);
finalization
 DeleteCriticalSection(CritSect);
end.


Глобальных переменных нет, есть локальные для модуля.


 
Тимохов ©   (2004-04-23 14:38) [39]


> Игорь Шевченко ©   (23.04.04 14:26) [38]

Можно замечание?
У вас все верно.
Т.е. заявленную функциональность класс делает - не дает созадать следующую копию.

Не все так просто имхо.
при вызове free выхов будет в последовательности:
beforedestruction;
desctuctor;
freeinstance.

Поэтому если к вашему примеру добавить содержательный деструктор, то будет лажа - деструктор будет отрабатывать каждый раз. Ну буду углубляться - думаю понятно, о чем я говорю.
Можете проверить...
Т.е. надо как-то воспротивится вызову destructor.
Скорее всего освобождение ресурсов надо делать прямо в freeinstance.


 
Locker   (2004-04-23 14:42) [40]

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TForm2 = class(TForm)
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   pForm: pointer;
 public
   constructor Create(a_Owner: TComponent); override;
   destructor Destroy; override;
 end;

implementation

{$R *.dfm}

{ TForm2 }

constructor TForm2.Create(a_Owner: TComponent);
const
 bForm: TForm2 = nil;
begin
 if (bForm <> nil) then
 begin
   Self := bForm;
   Self.BringToFront; // это чтобы нагляднее было
 end
 else
 begin
   inherited Create(a_Owner);
   pForm := @bForm;
   TForm2(pForm^) := Self;
 end;
end;

destructor TForm2.Destroy;
begin
 TForm2(pForm^) := nil;
 inherited;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree;
end;


 
Тимохов ©   (2004-04-23 14:45) [41]


> Locker   (23.04.04 14:42) [40]

на момент вызова create newinstance уже отработал, т.е. память взята.

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


 
Locker   (2004-04-23 14:53) [42]

Небольшие уточнения:

В конструкторе:
if (bForm <> nil) then
begin
  Self.Free;
  Self := bForm;
  Self.BringToFront; // это чтобы нагляднее было
end


В деструкторе:
 if (pForm <> nil) then TForm2(pForm^) := nil;


 
Игорь Шевченко ©   (2004-04-23 14:56) [43]


> Поэтому если к вашему примеру добавить содержательный деструктор,
> то будет лажа - деструктор будет отрабатывать каждый раз.
> Ну буду углубляться - думаю понятно, о чем я говорю.


Конечно, будет лажа. Поэтому содержательные деструкторы для таких объектов, например, освобождающие какие-то ресурсы, делать не надо. Я не говорил, что предлагаю универсальное решение.


 
Sha ©   (2004-04-23 14:58) [44]

> Тимохов ©   (23.04.04 14:38) [39]
>...добавить содержательный деструктор

Верно, но:

У Singleton класса не должно быть ни содержательного деструктора, ни содержательного конструктора.
Вся необходимая ининициализация и финализация делается
внутри NewInstance и FreeInstance.
По тем же причинам у него не должно быть наследников
при живом предке.


 
Locker   (2004-04-23 15:00) [45]

> работает ли ваш код

Как ни странно, работает. Если честно- то сам удивляюсь. Никогда такими изворотами не интересовался. А тут даже азарт появился... Эх, куда ж меня, в мои-то (хм...) годы!
А с учетом дополнений [42] и утечки памяти нет.
Но тогда приходится проверять некоторые условия в деструкторе, так как конструктор полностью не отработал. Но обычно (я про себя) такие проверки идут в любом деструкторе.


 
Тимохов ©   (2004-04-23 15:02) [46]


> Sha ©   (23.04.04 14:58) [44]

Я почтительно отношусь к науке программирования, но в данном случае имхо не совсем корректно говорить, что в таком-то паттерне условия такие потому как:
1. такой паттерн люди просто могут не знать.
2. в условии про него не было ничего сказано.

Порекоммендуйте что-нибудь почитать про эти преслувутые паттерны (покороче)?
Такое ощущение, что их действительно нужно знать, если уж на них дают задачи.


 
Тимохов ©   (2004-04-23 15:04) [47]


> Locker   (23.04.04 15:00) [45]

Жутко удивлен, но он действительно работает.
Надо понять в чем тут подвох, т.к. все-таки это какое имхо варварское отношение к дельфи :)))


 
Игорь Шевченко ©   (2004-04-23 15:08) [48]


> Порекоммендуйте что-нибудь почитать про эти преслувутые
> паттерны (покороче)?


Классика: Gang of Four Паттерны проектирования. (www.yandex.ru)


 
Sha ©   (2004-04-23 15:08) [49]

> Тимохов ©   (23.04.04 15:02) [46]
http://community.borland.com/article/0,1410,22576,00.html
http://www.castle-cadenza.demon.co.uk/single.htm


 
Vuk ©   (2004-04-23 15:11) [50]

to Игорь Шевченко ©   (23.04.04 14:56) [43]:
>Поэтому содержательные деструкторы для таких объектов, например,
>освобождающие какие-то ресурсы, делать не надо.
Хм... А кто мешает в конструкторе и деструкторе проверять тот же самый счетчик вызовов, который проверяется в New/FreeInstance?


 
Locker   (2004-04-23 15:13) [51]

>все-таки это какое имхо варварское отношение к дельфи

Согласен. Варварское. Лезть внутрь методов через указатели - варварство. Рабочее варварство.

Тут еще на какой-то ветке было обсуждение protected и private разделов. Это я к тому, что если захочешь - и в Private, и в Protected залезешь.

P.S. А, может, не варварство? Может, все-же хирургия? :)

P.P.S. Кстати... константа в конструкторе (с получением доступа через указатель) - случаем не аналог переменной класса (в том же C++)?


 
nikkie ©   (2004-04-23 15:14) [52]

>[44] Sha
странные какие-то требования. имхо, это не требования к паттерну Singleton (еще бы - откуда паттерн про NewInstance знает?), а ограничения, наложенные конкретной реализацией THSSingleton.


 
Андрей Сенченко ©   (2004-04-23 15:18) [53]

Хмм  ...

Издательство: "Питер"
Год издания: 2001, страниц: 368

Её вообще еще реально в продаже найти ?


 
Тимохов ©   (2004-04-23 15:20) [54]


> P.P.S. Кстати... константа в конструкторе (с получением
> доступа через указатель) - случаем не аналог переменной
> класса (в том же C++)?

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


 
Игорь Шевченко ©   (2004-04-23 15:23) [55]

Vuk ©   (23.04.04 15:11)
nikkie ©   (23.04.04 15:14)

С одной стороны, никто не мешает. Перенести счетчик ссылок в protected и проверять. С другой стороны лично мне такая реализация не нравится, когда в каждом деструкторе потомка надо проверять счетчик ссылок для выполнения каких-то действий. Класс этот изначально задумывался, как некий предок для хранения настроек (TSettings), поэтому содержательные деструкторы в нем не планировались.


 
Игорь Шевченко ©   (2004-04-23 15:24) [56]

Андрей Сенченко ©   (23.04.04 15:18) [53]

Я в магазине на "Войковской" видел.


 
SergLight ©   (2004-04-23 15:25) [57]


> Издательство: "Питер"
> Год издания: 2001, страниц: 368

У меня год издания 2003 (Серия "Библиотека программирования")


 
nikkie ©   (2004-04-23 15:26) [58]

>Класс этот изначально задумывался, как некий предок для хранения настроек (TSettings), поэтому содержательные деструкторы в нем не планировались.
как вариант: глобальная переменная, создаем объект в initialization, разрушаем в finalization, никто больше его не создает. зачем себе придумывать проблемы, чтобы потом их мужественно преодолевать?


 
Sha ©   (2004-04-23 15:27) [59]

> Vuk ©   (23.04.04 15:11) [50]
> А кто мешает в конструкторе и деструкторе проверять тот же
> самый счетчик вызовов, который проверяется в New/FreeInstance?

> nikkie ©   (23.04.04 15:14) [52]
> это не требования к паттерну Singleton (еще бы - откуда
> паттерн про NewInstance знает?), а ограничения, наложенные
> конкретной реализацией THSSingleton.

Просто значительно удобнее все проверять в одном месте.
Лично мне :)


 
vuk ©   (2004-04-23 15:29) [60]

to Игорь Шевченко ©   (23.04.04 15:23) [55]:
>Перенести счетчик ссылок в protected и проверять.
Ну не обязательно. Можно и в private оставить, сделав доступ на чтение через функцию, чтобы своим же шаловливым ручкам заранее не дать в потомках вмешаться в механизм. :o)


 
Игорь Шевченко ©   (2004-04-23 15:36) [61]

nikkie ©   (23.04.04 15:26)

Можно и так, как ты предлагаешь. Возможно разные пути решения проблемы (если проблема есть вообще). Кстати, можно проверять счетчик ссылок в перекрытом событии BeforeDestruction и если не равно 0, то вызывать Abort. А увеличивать счетчик ссылок в AfterConstruction, например.


 
Игорь Шевченко ©   (2004-04-23 15:48) [62]

vuk ©   (23.04.04 15:29)
nikkie ©   (23.04.04 15:26)

Раз зашел такой разговор, то подразумевается, что и в конструкторе надо запретить создание/выделение каких-то ресурсов больше одного раза ? У кого-то есть готовый способ ?

vuk ©   (23.04.04 15:29)

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


 
Игорь Шевченко ©   (2004-04-23 16:05) [63]


> Кстати, можно проверять счетчик ссылок в перекрытом событии
> BeforeDestruction и если не равно 0, то вызывать Abort


Не годится. А жаль


 
Sha ©   (2004-04-23 16:10) [64]

> Игорь Шевченко ©   (23.04.04 15:48) [62]
> Раз зашел такой разговор, то подразумевается, что и в
> конструкторе надо запретить создание/выделение каких-то
> ресурсов больше одного раза ? У кого-то есть готовый способ ?

Проще тогда генерировать исключение, как в http://www.castle-cadenza.demon.co.uk/single.htm


 
Игорь Шевченко ©   (2004-04-23 16:31) [65]

Sha ©   (23.04.04 16:10)

Хотелось бы прозрачно. Как вариант: vuk ©   (23.04.04 15:29) [60] , но получается, что потомки знают о механизме реализации предка, что тоже плохо


 
han_malign ©   (2004-04-23 16:39) [66]

>счетчика ссылок в деструкторе потомка
- если пошел разговор о потомках, то кто мешает еще раз перекрыть XXXInstance - так что разговор, на самом деле, ни о чем...

>запретить создание/выделение каких-то ресурсов больше одного раза
- можно конечно стек раскрутить - но это, IMHO, грубо - кулхацкерство одно... (по моему, достаточно Inc(ESP,4), хотя если фреймы  включены(или оптимизация выключена, и/или есть локальные переменные) - надо смотреть, но , кажись, ESP:=EBP[EBP](или просто EBP+4, если без фреймов, но с локальными)(разруливается через $IFOPT) - но это все надо смотреть, на вскидку утверждать не берусь)
- а вот с деструктором уже намного хуже...


 
han_malign ©   (2004-04-23 16:48) [67]

кстати, для HSSingleton можно без критической секции(ее таки инициализировать нужно), хотя, я сам постоянно забываю про - весьма полезные - InterlockedIncrement/Decrement...


 
Sha ©   (2004-04-23 16:53) [68]

han_malign ©   (23.04.04 16:48) [67]
В этом случае придется считать в отрицательную сторону :)


 
Sha ©   (2004-04-23 16:55) [69]

...начиная с 1


 
Игорь Шевченко ©   (2004-04-23 17:04) [70]


> можно без критической секции, я сам постоянно забываю про - весьма полезные - InterlockedIncrement/Decrement...


Не уверен


 
Sha ©   (2004-04-23 17:15) [71]


var
 Key: integer= 1;

class function THSSingleton.NewInstance: TObject;
begin;
 if InterLockedDecrement(Key)>=0
 then Instance:=THSSingleton(inherited NewInstance);
 Result:=Instance;
 end;

procedure THSSingleton.FreeInstance;
begin;
 if InterLockedIncrement(Key)>=0
 then begin;
   inherited;
   Instance:=nil;
   end;
 end;


 
Digitman ©   (2004-04-23 17:19) [72]

мьютексы, слава богу -  именованые объекты .. в их имени можно хранить Id процесса в строковом виде

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


 
Sha ©   (2004-04-23 17:20) [73]

поправка:
procedure THSSingleton.FreeInstance;
begin;
 InterLockedDecrement(Key);
 if InterLockedIncrement(Key)>=0
 then begin;
   inherited;
   Instance:=nil;
   end;
 InterLockedIncrement(Key);
 end;


 
Игорь Шевченко ©   (2004-04-23 17:27) [74]

Sha ©   (23.04.04 17:15)

Да, спасибо, вариант. Только читать непривычно :)


 
Sha ©   (2004-04-23 17:38) [75]

Но вариант с критической секцией мне нравится больше :)
он будет работать для нескольких потоков.
При доступе к моему варианту из нескольких потоков
два объекта не создастся, но возможен вариант, когда
второй поток может получить nil вместо адреса создаваемого
другим потоком объекта.


 
Verg ©   (2004-04-23 18:21) [76]


> Sha ©   (23.04.04 17:38) [75]


В данном случае крит.с не нужна в полном фунциональном объеме (рекурсивные вхождения). Так что, если нравится InterLocked..., то можно и с ними.

var Key : integer = 0;

...
 while InterLockedExchange(Key, 1) = 1 do sleep();
 // вошли в "КС"
 InterLockedExchange(Key,0);// вышли...

Можно и евентом с автосбросом, тогда и цикла со sleep не надо...


 
Sha ©   (2004-04-23 19:18) [77]

Verg ©   (23.04.04 18:21) [76]
Sleep не так красиво, а с Event мудренее и тяжелее:
крит. секция проскакивает почти всегда без wait"ов.


 
Verg ©   (2004-04-23 19:36) [78]


> Sleep не так красиво, а с Event мудренее и тяжелее:


Может и так - это дело вкуса:) Зато event можно именовать и сделать доступным и другим процессам (так, к слову)....

var Key : THandle; // createevent(nil, false, true, ....) (OpenEvent(....))

................
WaitForSingleObject(Key, INFINITE);
// вошли в "КС"
SetEvent(Key);// вышли...

Не так уж и "мудренее"...


 
Sha ©   (2004-04-23 19:47) [79]

Verg ©   (23.04.04 19:36) [78]
Я бы добавил try-finally.
Но, как уже говорил, предпочитаю крит.секцию, она менее ресурсоемка.


 
Verg ©   (2004-04-23 19:58) [80]


> она менее ресурсоемка.


Да? Есть основания так предпологать?
Я бы не осмелился....
Если она ведет учет того, какой поток именно ее захватил для обеспечния счетчика повторных вхождений, при этом таки заводит Event для ожидания освобождения, то уж всяко на "один квант" стоит дороже.
Не знаю точно про Windows, но опыт собственных "синхронизаторов" подсказывает, что критические секции обходятся несколько дороже, нежели элементарные "стоп - я сброшен".

Насчет try-finally - тут я полностью с тобой согласен :)) Просто за последние несколько дней на форумах у меня появилось ущущение, что эти блоки очень многие не любят, предпочитая goto и проч. :))))))))))


 
Sha ©   (2004-04-23 20:18) [81]

> Verg ©   (23.04.04 19:58) [80]
>> она менее ресурсоемка.
> Да? Есть основания так предпологать?

Ага, есть. Смотрел пару лет назад.


 
Игорь Шевченко ©   (2004-04-23 20:30) [82]

Verg ©   (23.04.04 19:58)

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


 
Игорь Шевченко ©   (2004-04-23 20:41) [83]

По поводу критических секций и Interlocked - я считаю, что операция проверки счетчика экземпляров, его изменение и выполнение каких-либо действий после проверки являет неделимой операцией, следовательно, защищать критической секцией надо операцию целиком. Мне кажется, что вариант с Intelocked-функциями может приводить к труднообнаруживаемым ошибками :)


 
Verg ©   (2004-04-23 21:03) [84]


>  Мне кажется, что вариант с Intelocked-функциями может приводить
> к труднообнаруживаемым ошибками :)


Зря кажется - это я тебе не "просто так" говорю :))))

В остальном...... - дело вкуса - как я уже говоил. Каждой задаче - свое решение....


 
Sha ©   (2004-04-23 22:02) [85]

> Verg ©   (23.04.04 21:03) [84]
> В остальном...... - дело вкуса - как я уже говоил. Каждой задаче - свое решение....

Подробнее.
Насколько помню, реализация критической секции для Intel сводится к следующему: это совокупность события, атомарного счетчика и данных, необходимых для отслеживания повторных входов(для нас это несущественно). При входе делаем InterlockedIncrement и анализируем результат: если можно пройти дальше, то проходим, если нет - встаем в ожидание. При выходе делаем InterlockedDecrement и анализируем результат: если в очереди кто-то есть, то его отпускаем.
При такой реализации почти никогда не будет работы с событием, что сказывается на производительности в лучшую сторону.
Можешь походить по коду под отладчиком а также сравнить время входа-выхода в критическую секцию со временем ожидания-сигнала отдельного события. Будешь приятно удивлен.
Так что не во вкусе дело :)


 
Игорь Шевченко ©   (2004-04-23 22:14) [86]

Verg ©   (23.04.04 21:03)

Не трудно будет привести замену критической секции InterLocked-фунциями в моем коде ? Или указать пост, где такая замена приведена.

Кроме всего прочего, мне лично кажется, что использование критической секции более наглядно. Впрочем, это дело вкуса, разумеется :)


 
Sha ©   (2004-04-23 23:26) [87]

> Игорь Шевченко ©   (23.04.04 22:14) [86]

Скока точно потоков обращаются к одиночке? Если больше одного, то его разорвут на части - никакой Interlocked не поможет. Надо иметь средство торможения всех, кроме одного.


 
nikkie ©   (2004-04-24 01:45) [88]

>[71] Sha
что-то я не могу понять глубинного смысла отсчета в обратную сторону, причем, начиная с единицы. почему было не сделать счетчик ссылок, как в TInterfacedObject или как было в THSSingleton?

тем более, я не понимаю смысла поправки [73] - зачем сначала Decrement, а потом два раза Increment? нельзя разве было написать просто
if InterLockedIncrement(Key)>0?

>Если больше одного, то его разорвут на части - никакой Interlocked не поможет.
безусловно. например, одновременный вызов FreeInstance в двух потоках может привести к утечке памяти - объект никогда не будет разрушен. только если понятно, что ни о какой потокозащищенности тут речи не идет, то зачем использовать Interlocked?


 
Verg ©   (2004-04-24 07:19) [89]


> Sha ©   (23.04.04 22:02) [85]


Нет, нет... подожди ка
> При входе делаем InterlockedIncrement и анализируем результат:
> если можно пройти дальше, то проходим, если нет - встаем
> в ожидание
. При выходе делаем InterlockedDecrement и анализируем
> результат: если в очереди кто-то есть, то его отпускаем.
>
> При такой реализации почти никогда не будет работы с событием,
> что сказывается на производительности в лучшую сторону.


Че-то я не понял: как же нет работы с событием, когда "встаем в ожидание". В ожидание-то как встаем? Чего и как ждем?


 
Verg ©   (2004-04-24 07:24) [90]


> Игорь Шевченко ©   (23.04.04 22:14) [86]



> Игорь Шевченко ©   (23.04.04 14:26) [38]
> unit HSSingleton;
>
> interface
>
> type
>  THSSingleton = class
>  private
>    FInstanceCount: Integer;
>  public
>    class function NewInstance: TObject; override;
>    procedure FreeInstance; override;
>  end;
>
> implementation
> uses
>  Windows;
>
> { THSSingleton }
>
> var
>  Instance: THSSingleton;
>  //CritSect: RTL_CRITICAL_SECTION;
>  key : integer = 0;
> procedure THSSingleton.FreeInstance;
> begin
>  while InterLockedExchange(key, 1) <>0 do sleep(1);//EnterCriticalSection(CritSect);
>  try
>    Dec(FInstanceCount);
>    if FInstanceCount = 0 then begin
>      inherited;
>      Instance := nil;
>    end;
>  finally
>    InterLockedExchange(Key, 0);//LeaveCriticalSection(CritSect);
>  end;
> end;
>
> class function THSSingleton.NewInstance: TObject;
> begin
>  Аналогично//EnterCriticalSection(CritSect);
>  try
>    if not Assigned(Instance) then
>      Instance := THSSingleton(inherited NewInstance);
>    Result := Instance;
>    Inc(Instance.FInstanceCount);
>  finally
>    Аналогично//LeaveCriticalSection(CritSect);
>  end;
> end;
>
>// initialization
>//  InitializeCriticalSection(CritSect);
>// finalization
>//  DeleteCriticalSection(CritSect);
> end.


 
Sha ©   (2004-04-24 09:14) [91]

Verg ©   (24.04.04 07:19) [89]
Ждем, конечно, события. Фишка в том, что ждем крайне редко, т.к. критическими секциями обычно защищают небольшие быстрые участки кода. Если же ждать приходится при каждом обращении, то и здесь мы ничего не теряем. Производительнеости будут равны. Но в этом случае стоит подумать - а на фига были нужны потоки: если мы все время ждем одного ресурса, то достаточно одного потока.


 
Sha ©   (2004-04-24 09:27) [92]

> nikkie ©   (24.04.04 01:45) [88]
> что-то я не могу понять глубинного смысла отсчета в обратную
> сторону, причем, начиная с единицы. почему было не сделать
> счетчик ссылок, как в TInterfacedObject или как было в THSSingleton?

Дело в том, что в возвращаемом результате InterlockedInc/Decrement гарантируется только знак. Считать можно и в прямую сторону, но только начиная с -2. Я выбрал первый из двух вариантов.

> тем более, я не понимаю смысла поправки [73] - зачем сначала
> Decrement, а потом два раза Increment? нельзя разве было
написать просто
if InterLockedIncrement(Key)>0?

Нет, по тем же причинам.

>> Если больше одного, то его разорвут на части - никакой Interlocked не поможет.
> безусловно. например, одновременный вызов FreeInstance в двух
> потоках может привести к утечке памяти - объект никогда не
> будет разрушен. только если понятно, что ни о какой
> потокозащищенности тут речи не идет, то зачем использовать Interlocked?

Ты прав, не обязательно. Можно обойтись Inc/Dec.
Просто, чуть выше han_malign ©   (23.04.04 16:39) [66] упомянул, что можно использовать Interlocked (конечно, имея ввиду однопотовый Singleton), в чем Игорь Шевченко ©   (23.04.04 17:04) [70] усомнился (имея ввиду многопотоковый вариант), и уже после этого я не поняв, что они не поняли друг друга, показал, как это могло бы выглядеть в случае с одним потоком :)


 
Sha ©   (2004-04-24 10:09) [93]

Verg ©   (24.04.04 07:24) [90]

Этот вариант проигрывает оригинальному по производительности.

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


 
Verg ©   (2004-04-24 10:59) [94]


> Sha ©   (24.04.04 10:09) [93]
> Verg ©   (24.04.04 07:24) [90]
>
> Этот вариант проигрывает оригинальному по производительности.


1. Оригинальный - это какой?
2. Поясни почему.


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


Покажи как. Странно это - "для двух". Что же это за синхронизация такая?


 
Sha ©   (2004-04-24 12:26) [95]

> Verg ©   (24.04.04 10:59) [94]
> 1. Оригинальный - это какой?

Игорь Шевченко ©   (23.04.04 14:26) [38]

> 2. Поясни почему.

В случае прохода секции без ожидания они равноценны - оба используют Interlocked. А в случае занятости ресурса твой вариант ждет в среднем на 0.5 msec больше.  

> Покажи как. Странно это - "для двух". Что же это за синхронизация такая?

Это хорошая разминка для мозгов. Сначала попробуй сам. В известной реализации для двух процессов, кажется, требуется 4 флажка. Вроде можно сделать для произвольного заранее известного числа. Можно ли обобщить на N процессов - не знаю.


 
Verg ©   (2004-04-24 12:58) [96]


> Sha ©   (24.04.04 12:26) [95]


Неужели не понятно, что там вместо sleep-а можно было поставить и событие с автосбросом. Дело-то не в слипе. Синхронизация там вовсе не за счет него происходит. Если б там sleep(0) поставил, то что? Ты бы сказал, что в среднем на 0 ms?

Кроме того


> Фишка в том, что ждем крайне редко,


Так что, как же будет в среднем? ;))


> Это хорошая разминка для мозгов. Сначала попробуй сам.


Не вижу ни смысла, ни интереса в этой задаче.


 
Sha ©   (2004-04-24 13:33) [97]

> Verg ©   (24.04.04 12:58) [96]

> Неужели не понятно, что там вместо sleep-а можно было
> поставить и событие с автосбросом. Дело-то не в слипе.

Почему же не понятно, очень даже понятно. В этом случае ты бы сэмулировал работу критической секции и производительности сравнялись бы :). Это тебе должно быть понятно после Sha ©   (23.04.04 22:02) [85] :)

> Синхронизация там вовсе не за счет него происходит. Если б там
> sleep(0) поставил, то что? Ты бы сказал, что в среднем на 0 ms?

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

>> Фишка в том, что ждем крайне редко,
> Так что, как же будет в среднем? ;))

Я думаю, ты сам сможешь ответить на этот вопрос, используя информацию из Sha ©   (23.04.04 22:02) [85] :)

>> Это хорошая разминка для мозгов. Сначала попробуй сам.
> Не вижу ни смысла, ни интереса в этой задаче

Тогда не надо было спрашивать как?


 
Verg ©   (2004-04-24 14:12) [98]


> Я бы сказал, что ты впустую ешь время CPU для достижения
> того же результата, что и критическая секция :)


Нет. И ты об этом знаешь и я уже говорил об этом, что того же результата, что и критическая секция простым "семафором" не добиться.

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

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


> Тогда не надо было спрашивать как?


Ах извини, конечно, бес попутал. Больше ничего не спрошу.


 
Sha ©   (2004-04-24 14:31) [99]

> Verg ©   (24.04.04 14:12) [98]
> Однако, когда рекурсивного вхождения не требуется...,
> то ответом на вопрос Игоря (о том как InterLocked...-том
> заменить КС) может служить мой ответ.

Не возражаю, но крит. секция быстрее. Только это и было сказано.

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

Другого ответа в общем случае я не знаю.
По-моему, для реализации многопоточного класса TSingleton лучше всего подходит именно критическая секция.


 
nikkie ©   (2004-04-24 15:11) [100]

Дело в том, что в возвращаемом результате InterlockedInc/Decrement гарантируется только знак.
в общем-то, да. на win95 и winNT3.51. на win98, winNT4.0 и выше гарантируется возврат правильного результирующего значения.

Считать можно и в прямую сторону, но только начиная с -2. Я выбрал первый из двух вариантов.
как это? получается реализация TInterfacedObject содержит грубейшую ошибку?


 
Sha ©   (2004-04-24 15:46) [101]

> nikkie ©   (24.04.04 15:11) [100]
> как это? получается реализация TInterfacedObject содержит грубейшую ошибку?

Почему ты так решил?


 
Sha ©   (2004-04-24 16:02) [102]

If the result of the increment is zero, the return value is zero.
If the result of the increment is less than zero, the return value is less than zero. If the result of the increment is greater than zero, the return value is greater than zero. A nonzero return value may not be equal to the result of the increment.

Можно использовать любой из переходов -N/0 или 0/+N.
Я обычно использую первый, TInterfacedObject - второй.
Всего получается 2х2=4 вариантов использования InterlockedIncrement/InterlockedDecrement.


 
Игорь Шевченко ©   (2004-04-24 18:11) [103]

А все-таки с критической секцией код читается легче, на мой взгляд :))

С уважением ко всем участникам,


 
default ©   (2004-04-24 21:00) [104]

блин, сразу видно что начальник дибил или инструктор по кадрам или кто там тебя спрашивал...
если кто-то что-то не знает это полная ерунда(если предпологалось решение через крит-ие секции), он может узнать это, возможно, за пару минут)главно способность обучаться)))


 
nikkie ©   (2004-04-24 21:54) [105]

>Sha
>Почему ты так решил?
потому, что ты сказал "Считать можно и в прямую сторону, но только начиная с -2", а TIntrefacedObject считает от 0. либо я чего-то не понимаю.

>Игорь Шевченко
>А все-таки с критической секцией код читается легче, на мой взгляд :))
дело не только в легкости чтения. просто код, использующий Interlocked..., в данном случае не является потокобезопасным - надо ведь еще синхронизировать доступ к Instance одновременно с изменением FInstanceCount. так что критическая секция необходима (если не стукнет воспользоваться для синхронизации объектами ядра, что здесь не к месту, конечно).


 
Юрий Зотов ©   (2004-04-24 22:06) [106]

> default ©   (24.04.04 21:00) [104]

Вообще-то, на работу обычно берут работать, а не учиться. Понятно, что на новом месте что-то осваивать все равно придется, но это смотря что осваивать. Если конкретный проект - это нормально, а вот если программирование - слишком дорогой работник получится.


 
Sha ©   (2004-04-24 22:12) [107]

> nikkie ©   (24.04.04 21:54) [105]
>> Почему ты так решил?
> потому, что ты сказал "Считать можно и в прямую сторону, но
> только начиная с -2"

Да согласен. Надо было выразиться точнее: "Используя переход -1/0 можно считать и в прямую сторону, но только начиная с -2".
Вообще в нашем случае можно было бы:
- используя переход -1/0 cчитать в прямую сторону, начиная с -2,
- используя переход 0/1 cчитать в прямую сторону, начиная с -1,
- используя переход -1/0 cчитать в обратную сторону, начиная с 1,
- используя переход 0/1 cчитать в обратную сторону, начиная с 2.

> а TIntrefacedObject считает от 0. либо я чего-то не понимаю.

У IntrefacedObject особый случай, где надо предпринять какие-либо действия - начало счета, т.е. шаг0. У нас же - шаг1, в этом-то все дело. Поэтому он свободно использует для освобождения переход из состояния 1 в состояние 0.

Перечитал свои посты в этой ветке - ужас, сколько неточностей. Кстати, ты был прав - та поправка не требовалась. Я перестраховался напрасно.


 
Sha ©   (2004-04-24 22:27) [108]

В смысле можно было написать:
procedure THSSingleton.FreeInstance;
begin;
if InterLockedIncrement(Key)>0
then begin;
  inherited;
  Instance:=nil;
  end;
end;



Страницы: 1 2 3 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.78 MB
Время: 0.038 c
7-1080470003
_dEMOn
2004-03-28 14:33
2004.05.16
Порты


1-1083078572
td
2004-04-27 19:09
2004.05.16
Как сделать событие на щелчок правой кнопкой мыши?


6-1080647659
SAG
2004-03-30 15:54
2004.05.16
UDPSocket не получает сообщение


1-1083061737
IceMaster
2004-04-27 14:28
2004.05.16
Memo


1-1083311423
M@X
2004-04-30 11:50
2004.05.16
Помогите перевести на паскаль с Си





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский