Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.03.13;
Скачать: CL | DM;

Вниз

Объясните мне про потоки и защищенность их методов!   Найти похожие ветки 

 
Aleksandr ©   (2003-03-03 10:21) [0]

Ну не могу я понять... Есть в программе штук семьдесят экземпляров одного и того же объекта-наследника TThread - отличается каждый тем, что работает с индивидуальным файлом, указанным при инициализации. Методы этих потоков - чтение/запись в эти файлы - приватные, доступен другим только один метод - помещение данных в эти потоки. Часть данных программы куда-то пропадала, я сделал логирование - все время проскакивает error I/O 32 или 5. В общем, получается, что в один метод в одно время кто-то обращается дважды. Объясните мне, глупому, может поток дважды одновременно войти в свой метод, или в каких истчо случаях может произойти "накладка" одновременного входа в один метод?


 
Digitman ©   (2003-03-03 10:26) [1]

ты хоть бы фрагмент кода привел


 
Aleksandr ©   (2003-03-03 12:30) [2]

2 Digitman c : Ох, ну если Вы настаиваете... Поймите правильно - кода там - многие тысячи строчек, поэтому, спрашивая о причинах проблемы, я, соответственно, не знаю, какую часть приводить. Ну, вот метод, где, как я предполагаю, все кроется:


procedure TRITableItem.CloseUpdateFile;
var
Ev : TRiEvent; //простой объект из полей команда/строка
AD : longint;
LastTimeOfs : longint;
S : TDosFileStream; //наследник файл-стрима, отличается тем, что в начале пишется идентификатор класса, "умеющего" читать данный экземпляр файла.
ReloadIndex : boolean;
begin
ReloadIndex:=false;
AD:=MasterTbl.GetTableTime(FIDT); //получить время последней метки времени из внешней коллекции
if NOT FileExists(UpdIndexfName) then
MakeIndexWithOutOpen; //, приватный метод, пересоздать индексный файл
LastTimeOfs:=IndexList.GetOffsetByLastTime(FIDT,FLastUpdWriteTime); //получить смещение от предыдущего изменения из внешней коллекции
if (LastTimeOfs>0) AND Assigned(FUpdFile) then begin //если открыт файл Handle FUpdFile
S:=TDosFileStream.Create(TmpDir+ChangeFileExt(ExtractFileName(UpdateFName),".tmp"),fmCreate);//создать временный файл
FUpdFile.Seek(0,soFromBeginning); //сместиться в файле апдейтов на начало
S.CopyFrom(FUpdFile,LastTimeOfs); //копировать из файла апдейтов во временный по смещение
while FSaveEvents.Count>0 do begin //пока количество изменений больше 0
S.Seek(0,soFromEnd); //отпозиционироваться на конец временного файла
try
Ev:=TRiEvent(FSaveEvents.Items[0]);
if Assigned(Ev) AND (Ev.Command=revMarkTime) then begin //если отметка времени
AddToIndexFile(Ev.GetDateTime,S.Position); //приватный метод, в индексный файл впихнуть позицию
ReloadIndex:=true
end;
S.Put(Ev); //записать во временный файл апдейт
Ev.Free
except
on E:Exception do
LogDBError(DBItemLogIDChar, "Close update file",E.Message+" " + TableName)
end;
FSaveEvents.Delete(0) //удалить из коллекции
end;
FUpdFile.Seek(LastTimeOfs, soFromBeginning); //сместиться в файле апдейтов на последнее изменение
S.Seek(0,soFromEnd); //сместиться на конец временного файла
while FUpdFile.Position<FUpdFile.Size do begin //от текущего до конца файла апдейтов
Ev:=TRiEvent(FUpdFile.Get);
S.Put(Ev); //записать во временный файл апдейт
S.Seek(0,soFromEnd); //сместиться на конец
Ev.Free
end;
S.Free; //закрыть временный
FreeAndNil(FUpdFile); //закрыть файл апдейтов
DeleteFile(PChar(UpdateFName)); //похерить файл апдейтов
MoveFile(PChar(TmpDir+ChangeFileExt(ExtractFileName(UpdateFName),".tmp")),PChar(UpdateFName));
//перенести временный как файл апдейтов
SetFileTimeStamp(UpdateFName,AD); //поставить время
SetFileTimeStamp(UpdIndexFName,AD) //поставить время
end;
FLastUpdWriteTime:=AD
end;



 
Digitman ©   (2003-03-03 12:48) [3]

ну, судя по тому, что ты получаешь отказы

ERROR_ACCESS_DENIED = 5
ERROR_SHARING_VIOLATION = 32

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

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

нужен как минимум еще код методов конструктора/деструктора потока и код метода Execute()

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


 
Dms   (2003-03-03 13:00) [4]

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


 
Aleksandr ©   (2003-03-03 13:56) [5]

Констракторы вызываются при запуске программы, дестракторы - при завершении. Потоки существуют в течение всего существования программы. Их Execute:

begin
while not Terminated do begin
while HaveWork and not Terminated do //если есть в коллекции объекты для обработки (просто возвращает Count>0
DoWork; // выполнить процедуру
if not Terminated then
Suspend
end;


DoWork включает в себя 3 метода: открытие файла, запись событий во временную коллекцию (FSaveEvents) и закрытие c сохранением (приведенный мной код). Есть доступный для других потоков метод, добавляющий объекты на обработку в коллекцию:

procedure TRITableItem.AddPutData( EvList : TCollectionList);
begin
EnterCriticalSection(FPutCS); //критическая секция, являющаяся внутренним свойством этого потока
try
while EvList.Count <> 0 do try
FPutQueue.Add( EvList.Items[0]) //в свою коллекцию вставить
finally
EvList.Delete(0)
end
finally
LeaveCriticalSection(FPutCS)
end
end;

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


 
Digitman ©   (2003-03-03 14:27) [6]

а крит.секция зачем нужна здесь ? поясни

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


 
SVM (Perm)   (2003-03-03 14:27) [7]

А к файлу FUpdFile доступ осуществляется только в контексте одного потока?


 
REA ©   (2003-03-03 14:45) [8]

Не знаю насколько совет в тему, но еще в Delphi есть фенечка TMutiReadExclusiveWriteSynchronizer, если надо общую память читать многими потоками, а писать одним.


 
Polevi ©   (2003-03-03 14:54) [9]

я бы Execute реализовал примерно так

while not Terminated do
begin
WaitForMultipleObjects(.. //ждем файл для обработки или признак завершения потока (needStopEvent,processFileSem)

if needStopEvent работу then break
else
begin
Извлекаем файл для обрабоки из списка
DoWork
end;

end


в основном потоке

processFileSem:=CreateSemaphore(nil,0,100,nil);
needStopEvent:=CreateEvent(nil,true,false,nil);

procedure AddFileToProcess(AFileName:string)
begin
AddFileToList(AFileName); //Добавляем файл для обработки в список
ReleaseSemaphore //первый свободный поток начнет обработку файла
end;



 
Polevi ©   (2003-03-03 14:59) [10]

PS
лучше так

procedure AddFileToProcess(AFileName:string);
begin
EnterCriticalSection
try
FFileList.Add(AFileName);
ReleaseSemaphore //первый свободный поток начнет обработку файла
finally
LeaveCriticalSection;
end;


 
REA ©   (2003-03-03 15:02) [11]

2Polevi:
может быть полезно
TThreadList represents a thread-safe list


 
Polevi ©   (2003-03-03 15:11) [12]

2REA © (03.03.03 15:02)
спасибо, я в курсе
в данном случае код с Enter, Leave нагляднее, IMHO


 
Aleksandr ©   (2003-03-03 18:54) [13]

Мда... сорри, что долго не подключался. Вижу, что много можно бы сделать иначе. Только по вопросу о критических секциях - если сделать глобальную критическую секцию, а потом использовать ее в для защиты метода потока - не получится ли, что 69 экземпляров потока будут ждать, пока 1 пройдет через этот код, при всем при том, что каждый экземпляр юзает сугубо свой файл?



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

Текущий архив: 2003.03.13;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.015 c
3-39155
Buben
2003-02-20 14:44
2003.03.13
For Select ... Do


14-39491
apple11
2003-02-25 06:50
2003.03.13
Почему D6 неправильно открывает проект ?


1-39266
_BasiL_
2003-03-03 16:41
2003.03.13
Variant


14-39463
Colt
2003-02-25 09:32
2003.03.13
Оптимальный инсталятор


14-39546
Михайлов Антон
2003-02-26 15:06
2003.03.13
Конвертор