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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.007 c
7-39592
edicon
2003-01-11 01:57
2003.03.13
Программирование Com-порта


14-39526
pcgamer
2003-02-26 11:45
2003.03.13
Кодеры () и дизайнеры. Давайте объединяться и обмениваться инфой.


3-39201
Dim!
2003-02-21 12:47
2003.03.13
Paradox в сети


1-39258
REA
2003-03-03 14:48
2003.03.13
Hints


3-39213
kalishenko stas
2003-02-20 19:19
2003.03.13
FastReport





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