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

Вниз

Проблем при использовнии потоков.   Найти похожие ветки 

 
Карелин Артем   (2003-10-07 10:19) [0]

Есть следующий код, при выполнении выполнении которого несколько раз возникает ошибка AV. Что не я делаю неправильно?
type
TSQLCounter = class(TThread)
private
FValue: integer;
FDatabase: TIBDatabase;
FTransaction: TIBTransaction;
FTempQ: TIBQuery;
procedure SetValue(const Value: integer);
procedure SetDatabase(const Value: TIBDatabase);
procedure SetTempQ(const Value: TIBQuery);
procedure SetTransaction(const Value: TIBTransaction);
published
property Value:integer read FValue write FValue;
private
property TempQ:TIBQuery read FTempQ write SetTempQ;
property Database:TIBDatabase read FDatabase write SetDatabase;
property Transaction:TIBTransaction read FTransaction write SetTransaction;
procedure FillQ;
{ Private declarations }
protected
procedure Execute; override;
end;

var
fBigSearch: TfBigSearch;
SQLCounter:TSQLCounter;

procedure TfBigSearch.Button1Click(Sender: TObject);
********
try
if SQLCounter<>nil then TerminateThread(SQLCounter.Handle,0);
finally
end;
SQLCounter:=TSQLCounter.Create(true);
with SQLCounter do
begin
OnTerminate:=OnThreadOff;
FreeOnTerminate:=true;
Priority:=tpLower;
Resume;
end;
********

procedure TSQLCounter.Execute;
begin
Synchronize(FillQ);
TempQ.Open;
Value:=TempQ.Fields[0].AsInteger;
Transaction.Commit;
Database.Close;
TempQ.Free;
Transaction.Free;
Database.Free;
Terminate;
end;

procedure TSQLCounter.FillQ;
begin
fBigSearch.StatusBar1.SimpleText:="Eaao iian?ao ?enea caienae.";
TempQ:=TIBQuery.Create(nil);
Database:=TIBDatabase.Create(nil);
Transaction:=TIBTransaction.Create(nil);
Database.Params.AddStrings(MainData.MainBase.Params);
Database.LoginPrompt:=false;
Database.DatabaseName:=MainData.MainBase.DatabaseName;
Transaction.DefaultDatabase:=Database;
Database.DefaultTransaction:=Transaction;
Database.SQLDialect:=3;
Database.Open;
Transaction.StartTransaction;
TempQ.Database:=Database;
TempQ.Transaction:=Transaction;
TempQ.SQL.Text:=StringReplace(fBigSearch.IBQuery1.SQL.Text,"*","count(*)",[rfReplaceAll]);
ShowMessage(TempQ.SQL.Text);
TempQ.Prepare;
TempQ.Params.Assign(fBigSearch.IBQuery1.Params);
end;

procedure TSQLCounter.SetDatabase(const Value: TIBDatabase);
begin
FDatabase := Value;
end;

procedure TSQLCounter.SetTempQ(const Value: TIBQuery);
begin
FTempQ := Value;
end;

procedure TSQLCounter.SetTransaction(const Value: TIBTransaction);
begin
FTransaction := Value;
end;

procedure TSQLCounter.SetValue(const Value: integer);
begin
FValue := Value;
end;

procedure TfBigSearch.OnThreadOff(Sender: TObject);
begin
if Sender<>SQLCounter then exit;
StatusBar1.SimpleText:="Iaeaaii "+IntToStr((Sender as TSQLCounter).Value)+" caienae.";
end;


 
Карелин Артем   (2003-10-07 10:22) [1]

Что не я делаю неправильно? Читать как Что я делаю неправильно?


 
Verg   (2003-10-07 10:29) [2]

С первого взгляда:

в ф-ции OnThreadOff не хватает SQLCounter:=nil;


 
HolACost!   (2003-10-07 10:30) [3]

Сдаётся мне, что ты провверяешь SQLCounter на nil, а оно у тебя так - где конструктор в котором эта фигня инициализируется или что-то хоть подобное?


 
Digitman   (2003-10-07 10:31) [4]


> Что я делаю неправильно


1. Создаешь объекты доступа к БД в основном потоке, а созданный при этом запрос пытаешься выполнить в дополнительном. Кр.того еще и уничтожаешь объекты доступа к БД не в том потоке, в котором они были созданы.

2. Не обрабатываешь потенциально возможные исключения в методе Execute

3. Не приводишь дословный текст сообщения об AV

4. Не предпринимаешь никаких попыток анализа причин AV, не трассируешь свой код


 
pasha_golub   (2003-10-07 11:19) [5]

Я бе еще добавил, что TerminateThread это функция аварийного завершения потока и она после себя мусора оставляет немерянно


 
Polevi   (2003-10-07 11:21) [6]

немерянно это сколько


 
pasha_golub   (2003-10-07 11:42) [7]

Это есть значит не измеряно, то есть не знаю :-))


 
Polevi   (2003-10-07 11:48) [8]

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


 
pasha_golub   (2003-10-07 11:58) [9]

2Polevi
Это вопрос спорный :-)


 
Digitman   (2003-10-07 12:01) [10]


> pasha_golub



> Это вопрос спорный


и каковы твои аргументы против утверждения <Polevi> ?


 
pasha_golub   (2003-10-07 12:07) [11]

2Digitman
У меня нет аргументов, но мне кажется что никто не мерял размер потеряной памяти, а следовательно не надо быть таким категоричным :-)


 
Карелин Артем   (2003-10-07 12:13) [12]

Digitman © (07.10.03 10:31) [4]
1)Не понял! Я же создаю обьекты доступа внутри вторичного потока. Поясни свое пост, ежели не трудно.
3)Нарушение доступ в модуле project1.exe по адресу 00000000 попытка чтения 00000000.
4)Вообще-то трассировал.

Ну а насчет TerminateThread: запрос у меня типа select count, выполняется долго и другого способа снять его я не вижу. Метод Terminate будет ждать завершения запроса.


 
Digitman   (2003-10-07 12:16) [13]


> мне кажется что никто не мерял размер потеряной памяти


да и "мерить" ее не надо ... достаточно иметь четкое представление о том, что как происходит при терминировании объектов "поток" и "процесс"

и, кстати, "память" - далеко не единственный ресурс, о котором идет речь в плане ресурсов


 
Verg   (2003-10-07 12:18) [14]


> 1)Не понял! Я же создаю обьекты доступа внутри вторичного
> потока. Поясни свое пост, ежели не трудно.


Не путай понятия. ВНУТРИ - это значит в контексте. Synchronize же как раз привод к тому, что метод в Sync выполняет клавный поток


> Метод Terminate будет ждать завершения запроса.


Не, ничего он ждать не будет


> Ну а насчет TerminateThread: запрос у меня типа select count,
> выполняется долго и другого способа снять его я не вижу.
>


А как тебе нравится хотя бы это?

If the target thread owns a critical section, the critical section will not be released.

Мне этого хватило, чтобы я как бы "забыл" про TerminateThread почти навсегда


 
Polevi   (2003-10-07 12:20) [15]

>Карелин Артем © (07.10.03 12:13) [12]
что по твоему делает Synchronize(FillQ);


 
Digitman   (2003-10-07 12:21) [16]


> 1)...Я же создаю обьекты доступа внутри вторичного
> потока


нет ! поскольку конструкторы их вызываются в контексте исполнения метода Synchronize(), то фактически исполнены они будут в том кодовом потоке, который самым первым вызвал TThread.Create, т.е. в данном случае - осн.код.поток


> 4)Вообще-то трассировал


что трассировал ? только код конструктора или ВСЕ методы потока ?


 
Карелин Артем   (2003-10-07 12:22) [17]

Verg © (07.10.03 12:18) [14]
Понял про контекст, исправлюсь.


 
pasha_golub   (2003-10-07 12:24) [18]

Digitman © (07.10.03 12:16) [13]

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


 
Verg   (2003-10-07 12:25) [19]


> Synchronize(), то фактически исполнены они будут в том кодовом
> потоке, который самым первым вызвал TThread.Create


2Digitman

На всякий случай: По крайней мере с D6 Synchronize методы выполняются ТОЛЬКО главным потоком (MainThread) вне зависимости от того, какой поток выполнил TThread.Create


 
Verg   (2003-10-07 12:28) [20]

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


 
Digitman   (2003-10-07 12:31) [21]


> запрос у меня типа select count, выполняется долго и другого
> способа снять его я не вижу


выполняется долго ? убедись в том, что нужные индексы созданы, корректны и эффективно используются сервером при исполнении запроса

корректные способы "снять" запрос есть.
по кр.мере - в IB/FB/YA
сходи на ibase.ru, там есть статьи на эту тему

терминируя же тред, ты ни коим образом не извещаешь сервер о том, что клиент более не нуждается результатах запроса и не ждет их. Сервер продолжает "молотить" запрос до тех пор, пока не наткнется на исключение тайм-аута и/или дисконнекта соединения с клиентом !


 
Владислав   (2003-10-07 12:38) [22]

> Карелин Артем © (07.10.03 10:19)

На первый взгляд, твоя проблема в этом:

FreeOnTerminate:=true;
...
if SQLCounter<>nil then TerminateThread(SQLCounter.Handle,0);

А вообще, код почти весь проблемный. Начиная с самого простого. Зачем в Execute вот это: Terminate; ?


 
Карелин Артем   (2003-10-07 12:41) [23]

>терминируя же тред, ты ни коим образом не извещаешь сервер о том, что клиент более не нуждается результатах запроса и не ждет их. Сервер продолжает "молотить" запрос до тех пор, пока не наткнется на исключение тайм-аута и/или дисконнекта соединения с клиентом !
Странно, ибо у меня сервер СРАЗУ прекращает выполнять запрос.
Индексы корректные и эффективные, данных может быть очень много.


 
Карелин Артем   (2003-10-07 12:43) [24]

Владислав © (07.10.03 12:38) [22]
Сам не знаю, зачем там это. Наверно справку по этому методу глядел и забыл удалить :(


 
Digitman   (2003-10-07 12:46) [25]


> Verg © (07.10.03 12:25) [19]


мне сложно проверить (не пользую Д6), но есть большие сомнения в этом

представим себе ситуацию - хост-процесс VB-приложения в доп.код.потоке вызвал некую эксп.ф-цию из Delphi-DLL. Ф-ция , разумеется, выполняется в том код.потоке, в котором она была вызвана. В теле ф-ции происходит самый первый вызов TThread.Create. В Д5 при этом создается невиз.окно, которое впоследствии будет как минимум принимать и обрабатывать сообщения синхронизации с вызывающим код.потоком. Без организации этого простейшего и наглядного механизма заставить вызывающий код.поток (не имеющий понятия ни о каких внутренних соглашениях Делфи и VCL !!) по какой-то неведомой ему заранее команде выполнить какую-то неведомую ему подпрограмму - задача весьма нетривиальная... было бы, конечно, прелюбопытно взглягуть, как "изголился" Борланд в Д6/Д7, решая эту задачу в своем обновленном супер-пупер классе TThread (и модуле, где все это действо творится)


 
Verg   (2003-10-07 12:57) [26]

Словами долго объяснять, я тут писал "доклад" про нововведения в D6. Почему-то уже потерто....

Вот, взгляни на два куска кода из classes. Я думаю тебе и так будет все понятно:

Вот такой Synchronize в D6:


var
ProcPosted: Boolean;
SyncList: TList = nil;
ThreadLock: TRTLCriticalSection;
ThreadCount: Integer;

procedure TThread.Synchronize(Method: TThreadMethod);
var
SyncProc: TSyncProc;
begin
if GetCurrentThreadID = MainThreadID then
Method
else
begin
{$IFDEF MSWINDOWS}
SyncProc.Signal := CreateEvent(nil, True, False, nil);
try
{$ENDIF}
{$IFDEF LINUX}
FillChar(SyncProc, SizeOf(SyncProc), 0); // This also initializes the cond_var
{$ENDIF}
EnterCriticalSection(ThreadLock);
try
FSynchronizeException := nil;
FMethod := Method;
SyncProc.Thread := Self;
SyncList.Add(@SyncProc);
ProcPosted := True;
if Assigned(WakeMainThread) then
WakeMainThread(Self);
{$IFDEF MSWINDOWS}
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);
finally
EnterCriticalSection(ThreadLock);
end;
{$ENDIF}
{$IFDEF LINUX}
pthread_cond_wait(SyncProc.Signal, ThreadLock);
{$ENDIF}
finally
LeaveCriticalSection(ThreadLock);
end;
{$IFDEF MSWINDOWS}
finally
CloseHandle(SyncProc.Signal);
end;
{$ENDIF}
if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;
end;


А разруливать этим SyncList-ом должна процедура:

function CheckSynchronize: Boolean;
var
SyncProc: PSyncProc;
begin
if GetCurrentThreadID <> MainThreadID then
raise EThread.CreateResFmt(@SCheckSynchronizeError,
[GetCurrentThreadID]);
if ProcPosted then
begin
EnterCriticalSection(ThreadLock);
try
Result := (SyncList <> nil) and (SyncList.Count > 0);
if Result then
begin
while SyncList.Count > 0 do
begin
SyncProc := SyncList[0];
SyncList.Delete(0);
try
SyncProc.Thread.FMethod;
except
SyncProc.Thread.FSynchronizeException := AcquireExceptionObject;
end;
{$IFDEF MSWINDOWS}
SetEvent(SyncProc.signal);
{$ENDIF}
{$IFDEF LINUX}
pthread_cond_signal(SyncProc.Signal);
{$ENDIF}
end;
ProcPosted := False;
end;
finally
LeaveCriticalSection(ThreadLock);
end;
end else Result := False;
end;


Здесь есть очч-ень глюкавое место, касающееся переменной


 
Digitman   (2003-10-07 12:57) [27]


> Карелин Артем


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

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


 
Карелин Артем   (2003-10-07 12:58) [28]

Вообще на Ibase.ru в факе есть пример есть по доступу к базам из разных потоков, но без принудительного завершения. На королевстве были примеры по завершению запросов, только запросы были внутри хранимых процедур и завершалось это дело при определенном значении генератора.


 
Владислав   (2003-10-07 13:03) [29]

> Digitman © (07.10.03 12:46) [25]

Это действительно так. Метод вызывается напрямую. По его адресу.


 
Verg   (2003-10-07 13:03) [30]

Здесь есть очч-ень глюкавое место, касающееся переменной
WakeMainThread

var
WakeMainThread: TNotifyEvent = nil;

Попробуй ка примени ее так, как советуют в help-е


Allows background threads to synchronize their execution with the main thread.

Unit

Classes

Category

thread management routines

function CheckSynchronize: Boolean;

Description

It is not necessary to call CheckSynchronize in a GUI application. The call to CheckSynchronize is made automatically by the application object. In a non-GUI application, you must call CheckSynchronize if you use the Synchronize method of TThread. To do this, set the WakeMainThread variable to a procedure that calls CheckSynchronize. CheckSynchronize allows background threads to synchronize their execution with the main thread, so that it is safe to make method calls in the background thread.

CheckSynchronize returns True if a method was synchronized, False if it does nothing.


Короче, грохнется все с AV, если написать так, как они советуют


 
Verg   (2003-10-07 13:03) [31]

Здесь есть очч-ень глюкавое место, касающееся переменной
WakeMainThread

var
WakeMainThread: TNotifyEvent = nil;

Попробуй ка примени ее так, как советуют в help-е


Allows background threads to synchronize their execution with the main thread.

Unit

Classes

Category

thread management routines

function CheckSynchronize: Boolean;

Description

It is not necessary to call CheckSynchronize in a GUI application. The call to CheckSynchronize is made automatically by the application object. In a non-GUI application, you must call CheckSynchronize if you use the Synchronize method of TThread. To do this, set the WakeMainThread variable to a procedure that calls CheckSynchronize. CheckSynchronize allows background threads to synchronize their execution with the main thread, so that it is safe to make method calls in the background thread.

CheckSynchronize returns True if a method was synchronized, False if it does nothing.


Короче, грохнется все с AV, если написать так, как они советуют


 
Polevi   (2003-10-07 13:06) [32]

>Digitman © (07.10.03 12:46) [25]

procedure TApplication.WakeMainThread(Sender: TObject);
begin
PostMessage(Handle, WM_NULL, 0, 0);
end;

в конструкторе TApplication
Classes.WakeMainThread := WakeMainThread;

{$IFDEF MSWINDOWS}
SyncProc.Signal := CreateEvent(nil, True, False, nil);
try
EnterCriticalSection(ThreadLock);
try
FSynchronizeException := nil;
FMethod := Method;
SyncProc.Thread := Self;
SyncList.Add(@SyncProc);
ProcPosted := True;
if Assigned(WakeMainThread) then
WakeMainThread(Self);
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);
finally
EnterCriticalSection(ThreadLock);
end;
finally
LeaveCriticalSection(ThreadLock);
end;
finally
CloseHandle(SyncProc.Signal);
end;

procedure TApplication.Idle(const Msg: TMsg);
var
Control: TControl;
Done: Boolean;
begin
...
...
if (GetCurrentThreadID = MainThreadID) and CheckSynchronize
...
...
end;

function CheckSynchronize: Boolean;
begin
...
...
while SyncList.Count > 0 do
begin
SyncProc := SyncList[0];
SyncList.Delete(0);
try
SyncProc.Thread.FMethod;
except
SyncProc.Thread.FSynchronizeException := AcquireExceptionObject;
end;
SetEvent(SyncProc.signal);


 
Digitman   (2003-10-07 13:07) [33]


> Verg


любопытно бы было еще взглянуть на текст WakeMainThread() и на инициализацию MainThreadId в контексте DLL

в Д5 переменная MainThreadId в DLL инициализируется ид-ром того потока, который грузит эту DLL (в случае, разумеется, сборки ее с RTP , в то время как хост-приложение может быть любым, даже не Делфи-приложением, и собранным с любыми опциями)


 
Polevi   (2003-10-07 13:07) [34]

упс

после
Classes.WakeMainThread := WakeMainThread;
идет код TThread.Synchronize


 
Владислав   (2003-10-07 13:09) [35]

> Verg © (07.10.03 13:03) [30]

"Короче, грохнется все с AV, если написать так, как они советуют"

Это почему? Какие тому причины?


 
Digitman   (2003-10-07 13:11) [36]

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


 
Digitman   (2003-10-07 13:15) [37]


> Владислав © (07.10.03 13:03) [29]
> > Digitman © (07.10.03 12:46) [25]
>
> Это действительно так. Метод вызывается напрямую. По его
> адресу.


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

совсем иной вопрос, КАКОЙ поток это сделает


 
Verg   (2003-10-07 13:16) [38]

Вот смотри.

Неглавный поток с FreeOnTerminate выполняет Synchronize
Кусок из Syncronize..

SyncProc.Thread := Self; // Обрати внимание!!!
SyncList.Add(@SyncProc); // !!!!!!!!
ProcPosted := True;
if Assigned(WakeMainThread) then
WakeMainThread(Self); // А в этой процедуре
мы вызовем CheckSinchronize, да пусть даже и не его, а просто в этой процедуре возникло исключение.

Из-за этого исключения наш поток завершит свою работу, а в силу FreeOnTerminate=true будет уничтожен как объект.
Далее, главный поток продолжает выполнять CheckSinchronize
Ха... А в SyncList-е сидит уже уничтоженный объект..


 
Владислав   (2003-10-07 13:17) [39]

> Digitman © (07.10.03 13:11) [36]

Ибо нефиг потоки в библиотеке плодить :)


 
Владислав   (2003-10-07 13:22) [40]

Он не уничтожиться, пока не выйдет из процедуры Synchronize.
А он из нее не выйдет, пока не закончиться CheckSynchronize.
Там критическая секция стоит.


 
Владислав   (2003-10-07 13:25) [41]

Даже не так. Если в WakeMainThread(Self); произойдет исключение, и оно не будет обработано, то и объект TThread уничтожен не будет.


 
Digitman   (2003-10-07 13:27) [42]


> Владислав


чегой-то вдруг ?)
а на кой шут мне тогда нужна эта VCL, если я не могу воспользоваться в общем-то неплохим классом TThread, избавляющим меня от массы рутинной работы ?)

не-е-е) ... ты не прав здесь !
просто для обхода этих неприятностей следует предпринять некие непредусмотренные Борландом (правда, не такие уж тривиальные) действия ... скажем, перехватить в хост-процессе любой WinAPI-вызов или оконное сообщение, и в обработчике перехвата :
- найти Id осн.код.потока процесса;
- сравнить с CurrentThreadId;
- если равны, то создать окно, диспетчеру сообщений которого впоследствии можно будет посылать тем или иным образом из прочих потоков сообщение с указанием выполнить такую-то процедуру/метод ... т.е. далее - по прямой аналогии с реализацией в Д5 ... разумеется, речь не идет о кросс-платформенности решения


 
Владислав   (2003-10-07 13:37) [43]

> Digitman © (07.10.03 13:27) [42]

Я, конечно же, пошутил.

Я бы поступил проще. Установил бы хук на сообщения главного окна приложения. В нем бы вызывал CheckSyncronize. А на WaikMainThread. Посылал бы главному окну приложения какое-нибудь сообщение. Хотя, простота, дело субъективное ;)


 
Verg   (2003-10-07 13:43) [44]


> Даже не так. Если в WakeMainThread(Self); произойдет исключение,
> и оно не будет обработано, то и объект TThread уничтожен
> не будет.



Да нет. С чего бы это? Будет уничтожен. Да еще как.

На ка, запусти:

program TestT;

uses
Windows,
Classes, Sysutils;

type
HostObject = class
procedure Dosome(Sender: TObject);
end;

MThread = class(TThread)
public
constructor Create;
procedure Execute; override;
procedure SomeMethod;
end;

procedure HostObject.Dosome(Sender: TObject);
begin
Abort;
end;

procedure MThread.SomeMethod;
begin
end;

constructor MThread.Create;
begin
FreeOnTerminate:=true;
inherited Create(false);
end;

procedure MThread.Execute;
begin
Synchronize(SomeMethod);
end;

Var Host : HostObject;
Mt : MThread;
begin
Host := HostObject.Create;
Classes.WakeMainThread:=Host.Dosome;
Mt:=MThread.Create;
while true do
begin
CheckSynchronize;
Sleep(500);
end;
end.


 
Verg   (2003-10-07 13:45) [45]

Там Abort можешь на CheckSinchronize заменить. Сути это не изменит.


 
Digitman   (2003-10-07 13:48) [46]


> Владислав


> сообщения главного окна приложения


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

тогда тебе вопросы ч.н. "на засыпку" :

- откуда ты знаешь, "главное" то или иное окно или "не главное" ? кто тебе об этом скажет, кроме разработчика non-Delphi-приложения ?

- а если приложение консольное и не создает явно никаких окон ? что будешь считать "главным" ?


 
Verg   (2003-10-07 13:54) [47]


> Digitman ©


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


 
Владислав   (2003-10-07 13:59) [48]

> Digitman © (07.10.03 13:48) [46]

"сообщения главному окну приложения"

Согласен. Некорректно выразился.

"тогда тебе вопросы ч.н. "на засыпку" "

Вопрос весь в том, я пишу библиотеку для какого то приложения, или разработчик собирается использовать мою библиотеку для своего приложения.
Для первого случая я вариант сказал. Winspertor Spy мне поможет с окном.
Для второго случая я предложил бы разработчику способ управлять потоками созданными в библиотеке. И написал бы в хелпе, как этим способом пользоваться. Это даже проще, чем первый вариант.

> Verg © (07.10.03 13:43) [44]

Это не показатель. Необработанное исключение внутри Execute так же приведет к AV. Так что, Борланд и там напортачило? Я думаю, это вполне корректный подход.


 
Verg   (2003-10-07 14:05) [49]


> Это не показатель. Необработанное исключение внутри Execute
> так же приведет к AV.


Да нет, ничего подобного.
Если произошло необработанное исключение в execute, то поток завершиться, а само объект исключение будет лежать у него в FatalException. Хотя если FreeOnTerminate=true, то и этот объект никому не нужен.


try
if not Thread.Terminated then
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
end;

finally
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.FFinished := True;
Thread.DoTerminate;
if FreeThread then Thread.Free;
.....


 
Verg   (2003-10-07 14:15) [50]


> Так что, Борланд и там напортачило?


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

Что вот это,
In a non-GUI application, you must call CheckSynchronize if you use the Synchronize method of TThread. To do this, set the WakeMainThread variable to a procedure that calls CheckSynchronize.

мягко говоря, неточность.

И что Synchronize с D6 - это со-о-овсем не тот Synchronize, что был раньше.


 
Digitman   (2003-10-07 14:21) [51]


> Verg © (07.10.03 13:54) [47]
> А скажи: на кой нам в DLL синхронизироваться с тем, кто
> вызвал некую процедуру из DLL и с кем мы ничего общего,
> кроме параметров этой процедуры не имеем?


а и не с ним вовсе (с тем, кто вызвал нас) нам синхронизироваться нужно !

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

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


 
Владислав   (2003-10-07 14:25) [52]

> Verg © (07.10.03 14:05) [49]

Да, согласен. Мое сообщение Владислав © (07.10.03 13:59) [48] не к тому месту было :)


 
Verg   (2003-10-07 14:33) [53]


> Мы не имеем никакого права асинхронно "трогать" этот ресурс
> , это чревато крахом процесса.


Этот ресурс должен быть защищен.
Ну в простейшем случае - критическая секция.

> Но скомандовать осн.потоку выполнить некие действия над
> ресурсом "от нашего имени" мы вправе


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


 
Digitman   (2003-10-07 15:19) [54]


> Verg



> Этот ресурс должен быть защищен


он и защищен хост процессом ... возможно ... но о механизме этой защиты наша ДЛЛ ничего не знает. поэтому вынуждена синхронизироваться с потоком, занявшим ресурс


> Тогда ОКП должен же дать какой-то механизм доступа "к себе".


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


 
Verg   (2003-10-07 15:44) [55]

Я думаю, что надо будет прибегнуть к тому же методу синхронизации, что и раньше, только самостоятельно "вручную".
Через такое же теневое окошко, которое будет создаваться где-либо в контексте вызывающего потока (да хоть в той же ф-ции или в DLLProc/DLL_PROCESS_ATTACH).


 
Digitman   (2003-10-07 15:55) [56]


> Verg


эт ты кому ? и по какому поводу ?


 
Verg   (2003-10-07 16:01) [57]


> Digitman © (07.10.03 15:55) [56]
>
> > Verg
>
>
> эт ты кому ? и по какому поводу ?


Тебе.
По поводу как из потока рожденного в фун-ции DLL синхронизироваться с потоком вызвавшим эту ф-цию.



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

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

Наверх





Память: 0.62 MB
Время: 0.008 c
14-65604
Denius
2003-09-29 17:49
2003.10.20
Расскажите про классы форм, пжалста!!!


3-65370
Dark Elf
2003-09-25 16:10
2003.10.20
Пароль и логин в TADOConnection


1-65519
Russko
2003-10-09 12:51
2003.10.20
TLabel


3-65363
MakNik
2003-09-24 15:24
2003.10.20
Аналог TOpenDialog


1-65440
Oleg_
2003-10-07 16:04
2003.10.20
аналог eval php





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский