![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Я никак не пойму в чем секрет, не работает DataSet
вова © (2014-01-04 18:46:00)Начинается все вот так:
destructor TObjectList.Destroy;
var
i: integer;
begin
FCount := 0;
SetLength(fTObjectsList, 0);
fTObjectsList := nil;
with GlobalShot do
begin
if not suspended then
begin
WaitForSingleObject(GlobalShot.MyMutex, INFINITE);
Terminate;
ReleaseMutex(GlobalShot.MyMutex);
// WaitFor;
end;
Free;
end;
if Length(fTObjectsList) > 0 then
for i := 0 to Length(fTObjectsList) - 1 do
begin
with fTObjectsList[i] do
begin
if not suspended then
begin
Terminate;
WaitFor;
end;
Free;
end;
end;
FCapacityAlph := 0;
FCountAlph := 0;
if Length(fTAlphabetsList) > 0 then
for i := 0 to Length(fTAlphabetsList) - 1 do
begin
fTAlphabetsList[i].Free;
end;
inherited;
end;
И код успешно доходит до fTAlphabetsList[i].Free; и заходит внутрь. Причем объекты в fTAlphabetsList это класс выполняющийся в основном потоке. А деструкторы классов которые удаляются выше с DataSet не работают. Да и в процессе своей работы тоже.
и вот
destructor TTextRecognize.Destroy;
begin
Form3.InsertNewSamplesInAlphabetSampleMassive(fName,fUnknownSymbols);
........
inherited;
end;
мы вызываем процедуру которая работает с DataSet в деструкторе класса.
в этой процедуре есть всего 2 места где идет обращение к DataSet
Function TForm3.InsertNewSamplesInAlphabetSampleMassive(ObjectName: String;
UnknownSymbolsArray: TSimpleSearchArray): boolean;
var
BufX: TSimpleSearchArray;
fSizeUS: integer;
pStart, pStop, pBuff: pWord;
m: word;
begin
UniFindRecord('ClientDataSet1', 'Name', ObjectName)
...........................
InsertNewSampleInDataSet3('KonturPicture', BufX) // вставляем
..........................
end;
Первая из них замечательно отрабатывает, на этот раз.
function TForm3.UniFindRecord(NameDataSet, ColName, ColValue: String): boolean;
Begin
If (not(GetDataSetParametr(NameDataSet, ColName) = ColValue)) then
begin
If not TClientDataSet(FindComponent(NameDataSet))
.Locate(ColName, ColValue, []) then
begin
if Debug then
MessageDlg('Значение ' + ColValue + ' в колонке " ' + ColName +
' " не найдено, добавьте в базу данных запись с таким значением в этой колонке!',
mtError, [mbOK], 0);
result := false;
end
else
result := true;
end
else
result := true;
end;
а во второй, я пытаюсь вычислить новый индекс строки для новой записи
maxSimb := GetMax_ImIndexClientDataSet3();
Function TForm3.GetMax_ImIndexClientDataSet3(): integer;
var
maxSimb: integer;
ObjectName :string;
begin
// Уникальность по всей базе
GetMax_ImIndexClientDataSet3 := 0;
maxSimb := 0;
ObjectName := GetDataSetParametr('ClientDataSet1', 'Name');
if ClientDataSet3.Filtered then
ClientDataSet3.Filtered := false;
//Form3.ClientDataSet1.DisableControls;
//Form3.ClientDataSet3.DisableControls;
Form3.ClientDataSet1.Last;
While Not Form3.ClientDataSet1.Bof Do
begin
Form3.ClientDataSet3.First;
While Not Form3.ClientDataSet3.Eof Do
begin
if ClientDataSet3.FieldByName('_ImIndex').value = Null then
begin
Form3.ClientDataSet3.Next;
continue;
end;
if Form3.ClientDataSet3.FieldByName('_ImIndex').value > maxSimb then
maxSimb := Form3.ClientDataSet3.FieldByName('_ImIndex').value;
Form3.ClientDataSet3.Next;
end;
Form3.ClientDataSet1.Prior;
end;
//Form3.ClientDataSet3.EnableControls;
//Form3.ClientDataSet1.EnableControls;
ClientDataSet1.Locate('Name', ObjectName, []);
//UniFindRecord('ClientDataSet1', 'Name', ObjectName);
GetMax_ImIndexClientDataSet3 := maxSimb;
end;
т.к. обнаружилось, что почему-то фокус с элемента ClientDataSet1 слетает после этой процедуры, то я запоминаю имя на котором мы были до выполнения процедуры: ObjectName := GetDataSetParametr('ClientDataSet1', 'Name');
И пытаемся восстановить его после (первый вариант, упрощенный от второго, дает тот же результат)
ClientDataSet1.Locate('Name', ObjectName, []);
или UniFindRecord('ClientDataSet1', 'Name', ObjectName);
и получаем ошибку First chance exception at $004033F9. Exception class $C0000005 with message 'access violation at 0x004033f9: read of address 0x0000fffc'. Process ******.exe (5224)
зато если просто вызвать
procedure TForm3.Button4Click(Sender: TObject);
var
BufX: TSimpleSearchArray;
begin
SetLength(BufX, 5);
UniFindRecord('ClientDataSet1', 'Name', 'LightGray');
//Form3.GetMax_ImIndexClientDataSet3(); а можно и так вызвать тоже работает.
InsertNewSampleInDataSet3('KonturPicture', BufX);
UniFindRecord('ClientDataSet1', 'Name', 'LightGray');
end;
то все пучком и все добавляется.....
че за фигня?
Причем если просто вызвать
RWolf (2014-01-05 20:39:00) [1]
> [28]
когда увеличивается размер массива, старые указатели вообще бесполезны, потому что весь массив переместился.
не нужно использовать указатели там, где достаточно индексов.
RWolf (2014-01-05 20:39:00) [2]
> [28]
когда увеличивается размер массива, старые указатели вообще бесполезны, потому что весь массив переместился.
не нужно использовать указатели там, где достаточно индексов.
вова (2014-01-05 20:38:00) [3]переделал pStart^ на sumBufX[i], пока вроде все тихо......ларчик то просто окрывался ) ошибка вылетает в деструкторе, а косяк в конструкторе )) причем совсем в другом месте.....
> класс нигде не выполняется. Выполняется код. Конкретно конструктор
> этого класса создаёт поток, исполняющий код метода TMyObject.
> Execute. Вызов Resume разбудит этот поток, если он ещё не
> работает (см. аргумент конструктора TThread).
тады чо он так вешает все.......конечно в обычном режиме не предполагается непрерывное создание и уничтожение потоков, но мало ли кому чего в голову придет, а у меня ошибка вылетает тогда (
RWolf (2014-01-05 20:28:00) [4]
> и я не понял, пока я не запустил Resume класс TMyObject
> = class(TThread) выполняется в основном потоке?
класс нигде не выполняется. Выполняется код. Конкретно конструктор этого класса создаёт поток, исполняющий код метода TMyObject.Execute. Вызов Resume разбудит этот поток, если он ещё не работает (см. аргумент конструктора TThread).
вова (2014-01-05 20:28:00) [5]ААААААААААААААА я понял наверное, когда я увеличиваю размер массива, необязательно, что место будет выделено прямо после конца предыдущего, и в результате inc(pBuff) будет указывать хз куда, может там чо то и затирается...хотя странно, почему ошибка тогда все время одна и та же...
вова (2014-01-05 20:25:00) [6]даже можно вот это не коментировать
TemplateStr := TemplateStr + GetDataSetParametr('ClientDataSet3', 'Object');
таким образом я в этом куске вообще не трогаю ДатаСет, чомля ему надо (
вова (2014-01-05 20:20:00) [7]жесть
в конструкторе TTextRecognize есть функция
Function TForm3.GetalphabetSampleMassive(ObjectName: String;
var sumBufX: TSimpleSearchArray; var TemplateStr: string): boolean;
var
BufX: TSimpleSearchArray;
vBlob: TStream;
fSizeUS: integer;
pStart, pBuff, PendBuff: pWord;
m: word;
begin
result := false;
If not UniFindRecord('ClientDataSet1', 'Name', ObjectName) then
exit;
fSizeUS := 0;
m := High(m) - 1; // знак начала шаблона в массиве.
SetLength(sumBufX, 1);
pStart := @sumBufX[0];
Form3.ClientDataSet3.DisableControls;
Form3.ClientDataSet3.First;
While Not Form3.ClientDataSet3.Eof Do
begin
vBlob := ClientDataSet3.CreateBlobStream
(ClientDataSet3.FieldByName('massSample'), bmRead);
SetLength(BufX, vBlob.Size div SizeOf(word));
try
vBlob.Seek(0, soFromBeginning); // sереход в начало потока BLOB
vBlob.ReadBuffer(BufX[0], vBlob.Size);
finally
vBlob.free;
end;
if Length(BufX) < 4 then
begin
Form3.ClientDataSet3.Next;
continue;
end;
TemplateStr := TemplateStr + GetDataSetParametr('ClientDataSet3', 'Object');
fSizeUS := fSizeUS + Length(BufX) + 1; { вычисляем новый размер массива, как
текущий размер + длина присоединяемого шаблона + место для m - знак начала
шаблона в массиве, и т.е. разделитель шаблонов }
SetLength(sumBufX, fSizeUS); // удлиняем массив
pStart^ := m;
// присваиваем ему значение признака начала нового символа в массиве
inc(pStart); // переходим на следующий элемент
pBuff := @BufX[0]; // становимся в первый элемент копируемого массива
PendBuff := @BufX[Length(BufX) - 1]; // запоминаем адрес последнего элемента
// шаблона
pStart^ := pBuff^;
repeat
inc(pStart);
inc(pBuff);
pStart^ := pBuff^;
until pBuff = PendBuff; // до тех пор, пока не дойдем до последнего элемента
Form3.ClientDataSet3.Next;
end;
Form3.ClientDataSet3.EnableControls;
result := true;
end;
так вот если в ней закоментировать вот этот кусок
TemplateStr := TemplateStr + GetDataSetParametr('ClientDataSet3', 'Object');
fSizeUS := fSizeUS + Length(BufX) + 1; { вычисляем новый размер массива, как
текущий размер + длина присоединяемого шаблона + место для m - знак начала
шаблона в массиве, и т.е. разделитель шаблонов }
SetLength(sumBufX, fSizeUS); // удлиняем массив
pStart^ := m;
// присваиваем ему значение признака начала нового символа в массиве
inc(pStart); // переходим на следующий элемент
pBuff := @BufX[0]; // становимся в первый элемент копируемого массива
PendBuff := @BufX[Length(BufX) - 1]; // запоминаем адрес последнего элемента
// шаблона
pStart^ := pBuff^;
repeat
inc(pStart);
inc(pBuff);
pStart^ := pBuff^;
until pBuff = PendBuff; // до тех пор, пока не дойдем до последнего элемента
то ошибка пропадает.....а что с этим куском не так?
Сергей М. (2014-01-05 20:08:00) [8]
> в TMyObject = class(TThread) работает только конструктор
> и деструктор
тогда нафих вообще нужен такой поток ?)
вова (2014-01-05 19:55:00) [9]поток точно один, убрал GlobalShot вообще, в результате в TMyObject = class(TThread) работает только конструктор и деструктор.
в fTAlphabetsList (в котором содержаться TTextRecognize = class)убрал вставление записей в дата Сет. Осталось только чтение в конструкторе. Впрочем как выяснилось, если не убирать то эффект будет тот же.
Результат: TMyObject вылетает в конструкторе с той же ошибкой. причем во второй итерации только, т.е. первый раз все выполняется, а второй уже ошибка. при условии, что сначала вызывается конструктор TTextRecognize = class, который также читает данные из дата сета.
А вот если вызов конструктора TMyObject будет перед TTextRecognize то тогда не вылетает ошибка, зато тогда нажатие на кнопку закончить отладку в RAD Studio приводит к зависанию делфи а через некоторое время выдает табличку что не удалось завершить процесс и выходим по аборту.... А если долго в цикле будет крутиться Create Free то в конце ошибка, что невозможно создать поток (
и я не понял, пока я не запустил Resume класс TMyObject = class(TThread) выполняется в основном потоке? Т.е. когда я вызываю из другого места его метод, то он будет вызван в основном потоке. ну а уж constructor TMyObject.Create(Name: string; Parent: TMyObject); тогда уж и тем более выполняется в основном потоке? тогда где может быть затык с DataSet?
или какая то там нить все равно создается и использовать его так не стоит? Потому что я тут уже этот вопрос задавал, ну то есть что в отдельный поток я его запускаю, только если он долго отрабатывает, а остальные экземпляры в основном работают. мне сказали можно так.....
вова (2014-01-05 18:59:00) [10]...вообщем с GetCurrentThreadId = MainThreadId я не удивился, они одинаковые перед любой ошибкой.
вова (2014-01-05 16:20:00) [11]
if GetCurrentThreadId = MainThreadId then
ClientDataSet1.Locate('Name', ObjectName, [])
else
maxSimb := maxSimb;
попробовал делать так, в else ниразу не попал, но и ошибка не вылазит в этом месте, ну то есть она теперь вылазит такая же и при такой же операции но в другом коде...
TMyObject = class(TThread) также обнаружил "блуждающий" глюк в этом классе, раньше он иногда появлялся, а теперь стабильно, не освобождается в деструкторе Tbitmap, а вылетает с ошибкой закоментировал уничтожение. результат выше.
Ладно буду курить всю эту хрень (
sniknik (2014-01-05 15:35:00) [12]> кроме того как показала практика если массив TMyObject не создавать, то и ошибки нет....
странная такая зависимость... и еще страньше что этот самый массив не участвует в обсуждении.
а вообще, что за фигня? зачем вопросы раз уверен, что у тебя все правильно? значит чудо, не спрашивай, фиксируй, и в Рим на канонизацию!
вова (2014-01-05 15:24:00) [13]форма с дата сетами существует все время, что существует программа и освобождается только вместе с закрытием программы. Никогда я не пытался освобождать их и даже удалять из них что-то програмно.
Сергей М. (2014-01-05 15:23:00) [14]
> ну выходит так
Да вот нифига не выходит, по твоим же утверждениям..
Перед вызовом Locate() сравни GetCurrentThreadId c MainThreadId и удивись.
вова (2014-01-05 15:19:00) [15]
> Пытаешься обратиться к ещё не созданному объекту или уже
> уничтоженому. Или обращаешься к индексу массива превышающего
> его размер.
я вызываю ClientDataSet1.Locate('Name', ObjectName, []); это....поэтому это не я пытаюсь обратиться к уже уничтоженному или что то там еще. Что я могу с этим поделать то? ) кроме того если потом зайти в базу, то строка с таким именем там замечательно существует.
вова (2014-01-05 15:17:00) [16]ну выходит так.....потому как я создаю класс TMyObject = class(TThread) который и содержится в fTObjectsList[i], но в resume я не делаю и execute он не выполняет.
а GlobalShot в отдельном потоке, но не контактирует с DataSet, т.е. в нем вообще ниодного обращения к нему нет, только TMyObject обращается к GlobalShot и забирает с него данные переодически и все.
кроме того как показала практика если массив TMyObject не создавать, то и ошибки нет....
Сергей М. (2014-01-05 15:07:00) [17]И все эти чудеса, как ты утверждаешь, происходят не иначе как в основном потоке ? Т.е. никакие доп.потоки в этом и при этом вообще не участвуют, так ?
Настоящий Вова (2014-01-05 15:05:00) [18]
> read of address 0x0000fffc
Пытаешься обратиться к ещё не созданному объекту или уже уничтоженому. Или обращаешься к индексу массива превышающего его размер.
вова (2014-01-05 15:00:00) [19]доходит до
ClientDataSet1.Locate('Name', ObjectName, []);
и следующим этапом вываливает что нибудь типа этого
> и получаем ошибку First chance exception at $004033F9. Exception
> class $C0000005 with message 'access violation at 0x004033f9:
> read of address 0x0000fffc'. Process ******.exe (5224)
причем после этого момента дата сет на любые манипуляции так реагировать начинает.
Сергей М. (2014-01-05 13:57:00) [20]Отладчик что говорит ?