Конференция "Базы" » Удаление TADOConnection в потоке [D7, MSSQL]
 
  • Артем (03.08.11 12:25) [20]

    > > CommandTimeOut и ConnectionTimeout не срабатывают
    > ???? у тебя, что пятая дельфя? только там, да и то без обновлений,
    >  была проблема с таймаутами. хотя, решаемая, правда через
    > генофонд.


    Пробовал в седьмой дельфи и XE, все равно не срабатывает таймаут.


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

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


    > > Есть функция .... бла.бла.бла.
    > меньше слов больше дел.. кода!

    Зачем тебе код этой функции?
    У меня был вопрос почему после уничтожения коннекта остаются User Handles.
  • DiamondShark © (03.08.11 12:27) [21]

    > sniknik ©   (03.08.11 11:56) [19]
    > > CommandTimeOut и ConnectionTimeout не срабатывают????
    > у тебя, что пятая дельфя?

    При чём здесь пятая дельфя? Он говорит про случай физической недоступности компьютеров. Здесь ни при чём не только дельфя, но и ни АДО ни МССКЛ дбпровайдер, ни дблиб. Это фича сокетов. Ну нету никакой возможности прервать сокетный connect(), ждущий ответа от недоступного хоста. Нету, хоть ты тресни.

    Инфа 100%, что при недоступности хоста ConnectionTimeout курит в углу, а управление возвращается, когда TCP-стек соблаговолит. Так себя ведёт и АДО с МССКЛ дбпровайдером, и ОДБЦ драйвер, дотНЕТ-клиент.
    А всё, сцуко, потому, что все они, в конце-концов, вызывают синхронный сокетный connect().
  • DiamondShark © (03.08.11 12:32) [22]

    > У меня был вопрос почему после уничтожения коннекта остаются
    > User Handles.

    А что такое, по-твоему, User Handles?
    Ну, вот, например, подсистема СОМ создаёт невидимые окна для обслуживания маршалинга. Окно -- это один из типов User Handle. Оно тебя сильно волнует?
  • DiamondShark © (03.08.11 12:43) [23]

    > Артем   (03.08.11 10:02) [18]

    Неправильно.

    Сделай функцию, которая принимает строку подключения, а вернуть должна экземпляр коннекта.
    Пусть функция создаёт экземпляр коннекта, настраивает параметры подключения и передаёт экземпляр в поток для открытия соединения.
    Потом функция пусть отсчитывает таймаут, и если поток не завершился, то устанавливает потоку флажок "коннект уже не нужен, удавись", и возвращяет NIL.

    А поток пусть ждёт подключения хоть до морковкина заговенья. Когда процедура потока получит возврат управления из Connection.Open(), она проверит флажок, если он сброшен, то просто оставит экзкмпляр коннекта в покое, а если установлен, то закроет соединение и разрушит экземпляр коннекта.
    В обоих исходах поток, в конце-концов, самоубъётся апстену.

    Не надо никаких разных потоков для подключения и уничтожения коннектов.
  • sniknik © (03.08.11 12:43) [24]
    > Зачем тебе код этой функции?
    ни этой, ни другой не нужно. нужно то что покажет реализацию полностью, хоть вообще без фунций

    > У меня был вопрос почему после уничтожения коннекта остаются User Handles.
    тебе ответили. нет закрытия без ожидания завершения операции, а если уничтожать "насильно" терминейтом то там вообще все будет не завершено, не освобождено.
    + таймаут, на "предвидение" очередного конекта в ту же сторону. стандартное поведение ADO.

    > При чём здесь пятая дельфя?
    в пятой не работало.
    > Он говорит про случай физической недоступности компьютеров.
    ну вот стоит у меня 30 сек, доступен, не доступен сервер мне не важно, через 30 отвалится - "кончилось время".  

    > Нету, хоть ты тресни.
    а зачем его прерывать? этого не нужно, сокеты всегда в своих потоках, имхо, все что ему нужно это дать ответ "ожидающему концу" через 30 сек.
    и опять имхо, именно так оно и работает. (не встречался с другим поведением... исключая 5ю дельфю)
  • Артем (03.08.11 12:48) [25]

    > А что такое, по-твоему, User Handles?
    > Ну, вот, например, подсистема СОМ создаёт невидимые окна
    > для обслуживания маршалинга. Окно -- это один из типов User
    > Handle. Оно тебя сильно волнует?

    Если честно, то я даже и не знаю что именно подразумевается под User Handles в Process Explorer.
    А так да, волнуют. Моя программа должна работать по несколько недель подряд. Представь себе сколько их накопится за это время, после этого наверное ОС сдохнет.

    Для эксперимента вызывал в AddObject сразу FreeAndNil(Obj). Коннект нормально удалился, хендлы тоже удалились. Также пробовал делать FObjList.Add(Obj), а потом FObjList.Delete(0), тоже все нормально удалилось. Но вот почему в процедуре Execute не так все хорошо удаляется.
  • Артем (03.08.11 12:50) [26]

    > Неправильно.
    >
    > Сделай функцию, которая принимает строку подключения, а
    > вернуть должна экземпляр коннекта.
    > Пусть функция создаёт экземпляр коннекта, настраивает параметры
    > подключения и передаёт экземпляр в поток для открытия соединения.
    >
    > Потом функция пусть отсчитывает таймаут, и если поток не
    > завершился, то устанавливает потоку флажок "коннект уже
    > не нужен, удавись", и возвращяет NIL.
    >
    > А поток пусть ждёт подключения хоть до морковкина заговенья.
    >  Когда процедура потока получит возврат управления из Connection.
    > Open(), она проверит флажок, если он сброшен, то просто
    > оставит экзкмпляр коннекта в покое, а если установлен, то
    > закроет соединение и разрушит экземпляр коннекта.
    > В обоих исходах поток, в конце-концов, самоубъётся апстену.
    >
    >
    > Не надо никаких разных потоков для подключения и уничтожения
    > коннектов.

    Спасибо, попробую.
  • sniknik © (03.08.11 13:00) [27]
    > Но вот почему в процедуре Execute не так все хорошо удаляется.
    другой поток, не инициализирована COM модель, обьект завязан на "чужую"... что хорошего может быть?

    > Спасибо, попробую.
    а нормально, на асинхронной/событийной логике слабо?
  • Артем (03.08.11 14:08) [28]
    unit ConnThread;

    interface

    uses
     Classes, ADODB, SysUtils, InterfacedThread, Windows, ActiveX;

    type
     TConnThread = class(TInterfacedThread)
     public
       Connection:TADOConnection;
       Connected:boolean;
       ConnectionString:string;
       FM:boolean; //из основного потока по
                   //этой переменной узнает что подключение есть
       destructor Destroy;  override;
       constructor Create(T:Boolean);
     private
       Flag:Boolean;
       { Private declarations }
     protected
       procedure Execute; override;
     published
     end;

    implementation

    constructor TConnЕhread.Create(T: Boolean);
    begin
     inherited;
     Flag:=False;
     CoInitialize(nil);
     Connection:=TADOConnection.Create(nil);
    end;

    destructor TConnThread.Destroy;
    begin
     if not Flag then
       if Assigned(Connection) then
         FreeAndNil(Connection);
     CoUninitialize;
     inherited;
    end;

    procedure TConnThread.Execute;
    begin
     try
       FM:=False;
       if Connected then
         Connection.Connected:=True
       else
         Connection.Connected:=False;
       FM:=True;
     except
     end;
    end;

    end.



    Все равно не удаляются хендлы. FreeOnTerminate стоит True.
  • sniknik © (03.08.11 14:16) [29]
    > //из основного потока по
    > //этой переменной узнает что подключение есть
    по данному коду его вообще никогда не будет... можно не парится с узнаванием.

    +
    создание потока и деструктор делаются в основном потоке вообще то... т.что в принципе ты ничего не изменил.

    ++
    а где Free?
  • sniknik © (03.08.11 14:18) [30]
    > а где Free?
    а, нашел.
  • Артем (03.08.11 15:09) [31]
    Поток создается в основном потоке, тут я только код самого потока подключения привел как советовал DiamondShark.


    > создание потока и деструктор делаются в основном потоке
    > вообще то... т.что в принципе ты ничего не изменил.

    Деструктор чего, потока или коннекта. Если потока, то для этого FreeOnTerminate в True установлено. Деструктор будет вызван когда закончиться выполнение процедуры Execute.
  • sniknik © (03.08.11 15:57) [32]
    > Если потока, то для этого FreeOnTerminate в True установлено.
    при чем здесь FreeOnTerminate,  у тебя опять CoInitialize делается не в том потоке в котором используется...
  • sniknik © (03.08.11 16:02) [33]
    вот для примера
    unit ConnThread;

    interface

    uses
    Classes, ADODB, SysUtils, Windows, ActiveX;

    type
     TConnThread = class(TThread)
     private
       Connection: TADOConnection;
     protected
       procedure Execute; override;
     public
       destructor Destroy;  override;
       constructor Create(CreateSuspended: Boolean);
     end;

    implementation

    constructor TConnThread.Create(CreateSuspended: Boolean);
    begin
     inherited;

     //CoInitialize(nil);
     //Connection:= TADOConnection.Create(nil);

     FreeOnTerminate:= true;
     Resume;
    end;

    destructor TConnThread.Destroy;
    begin
     //FreeAndNil(Connection);
     //CoUninitialize;

     inherited;
    end;

    procedure TConnThread.Execute;
    begin
     CoInitialize(nil);
     try
       Connection:= TADOConnection.Create(nil);
       FreeAndNil(Connection);
     finally
       CoUninitialize;
     end;
    end;

    end.



    и выполнить, до абсурда  

    uses ConnThread;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     i: integer;
    begin
     for i:= 1 to 1000 do
       TConnThread.Create(true);
    end;



    работает?
    а теперь закоментарь внутри Execute и раскоментарь в деструкторе/конструкторе... работает? или AV? (что возможно при "пересечениях" потоков. ну или у тебя очень быстрый комп... успевает, добавь нагрузку в Execute).
  • sniknik © (03.08.11 16:05) [34]
    > TConnThread = class(TThread)
    ???
    а как же декларируемая независимость от основного потока?
  • Игорь Шевченко © (03.08.11 18:14) [35]

    > у тебя опять CoInitialize делается не в том потоке в котором
    > используется


    мне кажется, должно быть CoInitializeEx (...COINIT_MULTITHREADED)
  • Артем (03.08.11 18:22) [36]

    > работает? а теперь закоментарь внутри Execute и раскоментарь
    > в деструкторе/конструкторе... работает? или AV? (что возможно
    > при "пересечениях" потоков. ну или у тебя очень быстрый
    > комп... успевает, добавь нагрузку в Execute).

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


    > мне кажется, должно быть CoInitializeEx (...COINIT_MULTITHREADED)

    Спасибо, надо почитать мануалы.
  • sniknik © (03.08.11 20:45) [37]
    > мне кажется, должно быть CoInitializeEx (...COINIT_MULTITHREADED)
    без разницы
    http://msdn.microsoft.com/en-us/library/ms695279%28v=vs.85%29.aspx
    ...
    The concurrency model and initialization options for the thread. Values for this parameter are taken from the COINIT enumeration. Any combination of values from COINIT can be used, except that the COINIT_APARTMENTTHREADED and COINIT_MULTITHREADED flags cannot both be set. The default is COINIT_MULTITHREADED.
    ...
    Because OLE technologies are not thread-safe, the OleInitialize function calls CoInitializeEx with the COINIT_APARTMENTTHREADED flag. As a result, an apartment that is initialized for multithreaded object concurrency cannot use the features enabled by OleInitialize.
    ...
    т.е. любом случае не обслуживает несколько потоков одной инициализацией, фактически VCL от мелкософта... ;)

    > У меня и раньше память ... бла.бла.бла.
    чем дальше, тем больше ощущение, что я тебе "про бабушку", а ты все "про дедушку" (уж куда более очевидно, проверил, да/нет ситуация такая, нет опять фигню свою несет)... и кому это надо? парься сам.
  • sniknik © (03.08.11 21:11) [38]
    Игорь Шевченко ©   (03.08.11 18:14) [35]
    можно чуток изменить тест, чтобы уж "по любому". на AV нарваться тут "дело техники", а вот так гарантированный глюк должен быть -
    unit ConnThread;

    interface

    uses
     Classes, ADODB, SysUtils, Windows, ActiveX;

    type
     TConnThread = class(TThread)
     private
       Connection: TADOConnection;
     protected
       procedure Execute; override;
     public
       destructor Destroy;  override;
       constructor Create(CreateSuspended: Boolean);
     end;

    implementation

    constructor TConnThread.Create(CreateSuspended: Boolean);
    begin
     inherited;

     //CoInitialize(nil);
     CoInitializeEx(nil, COINIT_MULTITHREADED);
     Connection:= TADOConnection.Create(nil);

     FreeOnTerminate:= true;
     Resume;
    end;

    destructor TConnThread.Destroy;
    begin
     FreeAndNil(Connection);
     CoUninitialize;

     inherited;
    end;

    procedure TConnThread.Execute;
    begin
     {CoInitialize(nil);
     try
       Connection:= TADOConnection.Create(nil);}


       //Connection.ConnectionString:= 'Provider=SQLOLEDB.1;Integrated Security=SSPI'; //mssql ëîêàëüíî
       Connection.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\;Extended Properties=Text'; //Jet
       Connection.Connected:= true;

     {  FreeAndNil(Connection);
       Sleep(0);
     finally
       CoUninitialize;
     end;}

    end;

    end.


    что делать понятно... 2 варианта.
  • Игорь Шевченко © (03.08.11 22:59) [39]
    sniknik ©   (03.08.11 20:45) [37]


    > без разницы


    CoInitialize calls CoInitializeEx and specifies the concurrency model as single-thread apartment.

    с разницей.


    > т.е. любом случае не обслуживает несколько потоков одной
    > инициализацией


    CoInitializeEx должна быть вызвана в самом потоке, который работает с OLE, COM, ADO, etc
 
Конференция "Базы" » Удаление TADOConnection в потоке [D7, MSSQL]
Есть новые Нет новых   [134431   +10][b:0][p:0.003]