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

Вниз

Как защитить переменные в потоке?   Найти похожие ветки 

 
Aleksandr   (2002-03-21 14:49) [0]

Уважаемые коллеги!
Может, я чего-то с методом тыка не понимаю...

Внутри Execute потока у меня есть переменная типа TMemoryStream, которая загружает информацию и передается в качестве параметра в создаваемый там же другой поток:

M:=TMemoryStream.Create;
Thread.Connection.ReceiveStream(M); //Thread - это переменная, которой и принадлежит Execute
with TUpdateProcessor.CreateOnStream(true,M) do begin //истчо один поток
FreeOnTerminate:=false;
UpdateType:=utRemoteUpdate;
Resume;
WaitFor;
UpdateResult:=UpdateType;
Free
end;

Суть проблемы в том, что потоков, выполняющих этот код, может быть несколько, и, хотя М является локальной переменной, при трассировке программы она после передачи в TUpdateProcessor уже в его теле принимает значения, которые считывает из сокета другой экземпляр Thread. Другой пример: в этом же коде все время ведется лог в текстовый файл, открытый fmOpenReadWrite or fmShareDenyNone. В этот лог разные экземпляры потока тоже одновременно рисуют, то есть вместо
14:40:10: Обработка обновлений 0001...
14:40:11: Обработка 0001 успешно завершена
14:40:12: Обработка обновлений 0002...
14:40:13: Обработка 0002 успешно завершена
пишется
14:40:10: Обработка обновлений 0001...
14:40:11: Обработка обновлений 0002...
14:40:12: Обработка 0001 успешно завершена
Попробовал я засунуть код в рамки CriticalSection, дык он тогда вообще просто умирает. В чем тут смысл жизни?


 
Виктор Щербаков   (2002-03-21 15:01) [1]

threadvar


 
Aleksandr   (2002-03-21 15:14) [2]

Низя threadvar внутри метода объявлять :(


 
Виктор Щербаков   (2002-03-21 15:20) [3]

А зачем внутри метода?


 
Digitman   (2002-03-21 15:21) [4]

не понял - приведенный тобой код предст.собой фрагмент тела TThread.Execute, так что ли ?


 
Aleksandr   (2002-03-21 15:27) [5]

Мда, и в самом деле...
Ну, вот например... Когда файл лога зашкаливает за размер, его надо убить и пересоздать. Файл лога - это приватное поле потока типа TFileStream:
if FLogFile.Size>MaxLogFileSize then begin
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone)
end;
Проверка на размер внутри метода добавления записей в лог. Но у меня этот код не срабатывает - файл застывает на данном размере и больше не двигается... Очевидно, происходит исключительная ситуация с тем, что пока выполняется этот код, поток успевает опять вызвать добавление записи в лог... И как тут запретить ему дважды входить в метод?


 
Aleksandr   (2002-03-21 15:28) [6]

2 Digitman - Да


 
Виктор Щербаков   (2002-03-21 15:32) [7]


> И как тут запретить ему дважды входить в метод?

С помощью критических секций или объектов ядра.


 
Aleksandr   (2002-03-21 15:55) [8]

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


 
Digitman   (2002-03-21 15:58) [9]

>Aleksandr

т.е., полностью это выглядит вот так ?


procedure TSomeThread.Execute;
var
M: TMemoryStream;
begin
M:=TMemoryStream.Create;
Thread.Connection.ReceiveStream(M); // Thread = Self ? И зачем это ?
with TUpdateProcessor.CreateOnStream(true,M) do begin
FreeOnTerminate:=false;
UpdateType:=utRemoteUpdate;
Resume;
WaitFor;
UpdateResult:=UpdateType;
Free
end;
end;


если - так (а с твоих слов - именно так !), то о какой вообще синхронизации может идти речь ? Ну, создал ты MemoryStream, передал его параметром в другой поток - так ведь ждешь все равно, пока другой поток не завершится ? А завершился - продолжай работать с MemoryStream, ничто этому не мешает. Кстати, и не уничтожаешь ты MemoryStream нигде - если это не делается в TUpdateProcessor, утечка памяти тебе гарантирована.


 
Aleksandr   (2002-03-21 16:08) [10]

Нет, полный код, конечно, не такой... Thread - это не Self, это параметр Execute для IdTCPServer - его метод присваивается создаваемому потоку каждого клиентского соединения... А память освобождается внутри апдэйтора... А что с синхронизацией?


 
Aleksandr   (2002-03-21 16:21) [11]

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


 
Digitman   (2002-03-21 16:25) [12]

какой еще "параметр" ? Нет у TThread.Execute параметров ! Выражайся точнее


 
Aleksandr   (2002-03-21 16:46) [13]

Заранее извиняюся за спам...

unit Webthreads;
interface
type
TWebDataProcessor=class (TThread)
private
FSleepInterval : word;
FDir : string;
FClient : TIdTCPClient;
FBadDir : string;
FLogFile : TFileStream;
FLogFileName : string;
public
constructor Create(ASuspensed : boolean; ASleepInterval : longint;ADir : string; AHost : string; APort : word);
procedure Execute; override;
destructor Destroy; override;
function SendFile(AFileName : string) : boolean;
procedure AddLog(Msg : string);
published
property BadDir : string read FBadDir write FBadDir;
end;

TRsWebServer=class (TIdTCPServer)
private
FBadDir : string;
FLogFile : TFileStream;
FLogFileName : string;
procedure FOnExecute(AThread: TIdPeerThread);
public
constructor CreateOnPort(APort : word);
destructor Destroy; override;
procedure AddLog(Msg : string);
published
property BadDir : string read FBadDir write FBadDir;
end;

const
RSFileName="$FileNameOK";
RSFileSize="$FileSizeOK";
RSFileData="$FileDataOK";
RSUpdError="$UpdatError";
WebSrvLogFileName = "websrv.log";
WebStmLogFileName = "webstrm.log";

var
WebSection1 : TRTLCriticalSection;
FileSection1 : TRTLCriticalSection;
FileSection2 : TRTLCriticalSection;

implementation

constructor TRsWebServer.CreateOnPort(APort: word);
begin
Inherited Create(nil);
DefaultPort:=APort;
FLogFileName:=CorrectPath(LogFilesDir)+WebSrvLogFileName;
if FileExists(FLogFileName) then begin
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone);
if FLogFile.Size>30000 then begin
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
end;
FLogFile.Free
end
else begin
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
FLogFile.Free
end;
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone);
FLogFile.Seek(0,soFromEnd);
InitializeCriticalSection(FileSection2);
OnExecute:=FOnExecute
end;

procedure TRsWebServer.AddLog(Msg: string);
var
s : string;
P : Pointer;
begin
if NOT Assigned(FLogFile) then
Exit;
try
EnterCriticalSection(FileSection2);
if FLogFile.Size>30000 then begin
FlogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone)
end;
S:=DateTimeToStr(Now)+": "+Msg+#13#10;
P:=Pointer(s);
FLogFile.WriteBuffer(P^,length(S))
finally
LeaveCriticalSection(FileSection2)
end
end;

procedure TRsWebServer.FOnExecute(AThread: TIdPeerThread);
var
aFileName : string;
AuID : integer;
aFileSize : integer;
M : TDosMemoryStream;
s : string;
UType : TUpdateType;
begin
try
try
M:=TDosMemoryStream.Create;
AFileName:=AThread.Connection.Readln;
AThread.Connection.Writeln(rsFileName);
aFileSize:=StrToIntDef(AThread.Connection.ReadLn,-1);
AThread.Connection.Writeln(rsFileSize);
AThread.Connection.ReadStream(M,AFileSize);
AThread.Connection.Writeln(RSFileData);
M.Seek(0,soFromBeginning);
if M.Size>0 then begin
s:=ExtractFileName(AFileName);
s:=System.Copy(S,1,Pos(".",S)-1);
aUID:=StrToInt("$"+S);
AddLog("


 
Aleksandr   (2002-03-21 16:47) [14]

Продолжение:


{ TWebDataProcessor }
function TWebDataProcessor.SendFile(AFileName: string): boolean;
var
R : TRiHeader;
F : TFileStream;
s : string;
begin
Result:=false;
R:=nil;
try
R:=TRIHeader(GetFromFileStream(AFileName));
F:=nil;
if FileExists(R.TransName) then begin
FClient.Writeln(ExtractFileName(R.TransName));
s:=FClient.ReadLn;
if s=rsFileName then try
F:=TFileStream.Create(R.TransName,fmOpenRead OR fmShareDenyNone);
FClient.Writeln(IntToStr(F.Size));
s:=FClient.Readln;
if s=rsFileSize then begin
FClient.WriteStream(F);
s:=FClient.ReadLn;
if s=rsFileData then
Result:=true
else
AddLog("Error file data ok - "+R.TransName)
end
else
AddLog("Error file size ok - "+R.TransName)
finally
F.Free
end
else
AddLog("Error file name ok - "+R.TransName)
end
else
AddLog("File Not found - "+R.TransName)
finally
if Result then begin
DeleteFile(R.TransName);
DeleteFile(AFileName)
end
else if FBadDir<>"" then begin
DeleteFile(AFileName);
{$IFNDEF Remote}
MoveFileWithUnicName(R.TransName,FBadDir+ExtractFileName(R.TransName))
{$ENDIF}
end;
R.Free
end
end;

constructor TWebDataProcessor.Create;
begin
inherited Create(true);
FreeOnTerminate:=false;
FSleepInterval:=ASleepInterval;
FDir:=ADir;
FClient:=TIdTCPClient.Create(nil);
FClient.Port:=APort;
FClient.Host:=AHost;
FLogFileName:=CorrectPath(LogFilesDir)+WebStmLogFileName;
if FileExists(FLogFileName) then begin
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone);
if FLogFile.Size>30000 then begin
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
end;
FLogFile.Free
end
else begin
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
FLogFile.Free
end;
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone);
FLogFile.Seek(0,soFromEnd);
InitializeCriticalSection(WebSection1);
InitializeCriticalSection(FileSection1);
if NOT ASuspensed then
Resume
end;

procedure TWebDataProcessor.AddLog(Msg: string);
var
s : string;
P : Pointer;
begin
if NOT Assigned(FLogFile) then
Exit;
try
EnterCriticalSection(FileSection1);
if FLogFile.Size>30000 then begin
FlogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmCreate);
FLogFile.Free;
FLogFile:=TFileStream.Create(FLogFileName,fmOpenReadWrite or fmShareDenyNone)
end;
S:=DateTimeToStr(Now)+": "+Msg+#13#10;
P:=Pointer(s);
FLogFile.WriteBuffer(P^,length(S))
finally
LeaveCriticalSection(FileSection1)
end
end;

procedure TWebDataProcessor.Execute;
var
HeadersList : TList;
FData : PWin32FindData;
i : integer;
s : string;
begin
Sleep(0);
try
Repeat
HeadersList:=TList.Create;
if SearchFiles32(HeadersList,FDir+HeadersMask) then try
AddLog("Found file(s) to send - "+IntToStr(HeadersList.Count));
EnterCriticalSection(WebSection1);
for i:=0 to HeadersList.Count-1 do try
FData:=HeadersList.Items[i];
if NOT FClient.Connected then
FClient.Connect;
AddLog("Connected to remote...");
if FClient.Connected AND FileExists(CorrectPath(FDir)+ExtractFileName(FData.cFileName)) then begin
s:=CorrectPath(FDir)+ExtractFileName(FData.cFileName);
if SendFile(CorrectPath(FDir)+ExtractFileName(FData.cFileName)) then
AddLog("File sending successfully - "+s)
else
AddLog("File cannot sending - "+s)
end
else if NOT FClient.Connected then
AddLog("Connection unavailable");
if FClient.Connected then begin
AddLog("Disconnected to remote.");
FClient.DisConnect
end;
Dispose(FData);
finally
end
finally
LeaveCriticalSection(WebSection1);
end;
while HeadersList.Count>0 do
HeadersList.Delete(0);
HeadersList.Free;
Sleep(FSleepInterval);
until Terminated
except
on E:Exception do
AddLog("Exception in execute - "+E.Message)
end
end;

destructor TWebDataProcessor.Destroy;
begin
if Assigned(FClient) then
FClient.Free;
DeleteCriticalSection(WebSection1);
DeleteCriticalSection(FileSection1);
inherited
end;

end.


 
Digitman   (2002-03-21 17:25) [15]

А чито это меняет ? M - локальная переменная в процедуре обработки события. До тех пор, пока не отработает TDBUpdateProcessor.Execute, никто и ничто больше, судя по коду, не обращается к M. Для чего ж синхронизация-то доступа к M ?


 
Aleksandr   (2002-03-21 17:40) [16]

Тем не менее, получается, что он же и обращается к ней либо не ждет завершения DBUpdateProcessor+потока...
Например, если я сделаю в конце Execute освобождение M.Free, то в Execute DBUpdateProcessora будет Access Violation - там Stream окажется никакой. Хотя уничтожение должно произойти только после отработки :(


 
Digitman   (2002-03-21 17:49) [17]

так это ж - совсем иная проблема !
приводи код класса TDBUpdateProcessor - там посмотрим, чего он там "висит" (так что дождаться его завершения невозможно по WaitFor)


 
Aleksandr   (2002-03-21 18:05) [18]

Ох... там кода и на пять отправок не полезет... У меня главная проблема в том, что вот в приведенном коде есть три проблемы:
1) когда файл лога перескакивает предел, винды убивают программу.
2) программа очень быстро съедает все ресурсы процессора.
3) все время растет память программы.
Проблемы - в этом модуле, если его выключить из основной, то все становится ок.


 
Digitman   (2002-03-21 18:35) [19]

Нет, ну а какое это отношение к синхронизации доступа к M имеет ? Ты ж ведь так именно вопрос поставил ? Давай уж с этим разберемся, а уж потом логом займемся ....

Еще раз :

M - локальна в вызывающей процедуре, содержит ссылку на объект.
Ты передаешь значение M параметром в конструктор другого объекта-потока, и, пока этот "другой" поток не завершится, ты нигде к M не обращаешься в вызывающем коде. В вызванном потоке, я предполагаю, идет обращение к объекту M без его уничтожения в финале. О завершении же созданного "другого" потока тебе сообщит успешное завершение вызова метода WaitFor. Он (WaitFor) у тебя успешно завершается ??



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

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

Наверх





Память: 0.51 MB
Время: 0.006 c
1-120
dr_neo
2002-03-21 17:45
2002.04.01
Взлом программ! ! !


6-259
SemFLY
2002-01-18 21:05
2002.04.01
Передача файлов через Socket.


3-36
TYuri
2002-03-07 10:26
2002.04.01
Help, помогите срочно нужна помощь!


14-302
Алексей Петров (M)
2002-02-15 11:56
2002.04.01
2 Merlin: Убери, Please, от меня большую синию (M)


1-163
Max
2002-03-22 08:32
2002.04.01
Delphi 5 + W2k





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