저는 Delphi XE2를 사용하고 있으며 내 응용 프로그램은 twitter / rss의 새 레코드에 대해 알리는 데 사용됩니다. 내 응용 프로그램에서는 2 개의 스레드를 사용하여 매초 트위터 및 RSS에서 데이터를 가져옵니다.
다음은 코드입니다.
유형 섹션 :
TWarframeEvent=record
GUID: String;
EventType: Byte; // 0 = unknown; 1 = alert; 2 = invasion; 3 = infestation
Planet: String;
Mission: String;
EventDate: TDateTime;
Time: Integer;
RewardCredits: LongWord;
RewardOther: String;
RewardOtherAmount: Integer;
Notified: Boolean;
ItemIndex: Integer;
Hidden: Boolean;
end;
TWarframeNotifyEvent=record
NotifyTimeLeft: LongWord;
ID: Integer;
FlashOnTaskbar: Boolean;
PlaySound: Boolean;
Volume: Integer;
TrayPopupBalloon: Boolean;
end;
TWarframeEventList=record
WarframeEvent: Array of TWarframeEvent;
WarframeEventCount: Integer;
NotifyEvent: TWarframeNotifyEvent;
end;
TUpdateFromTwitterThread=class(TThread)
TwitterURL: String;
Procedure Execute; override;
end;
TUpdateFromRSSThread=class(TThread)
RSS_URL: String;
Procedure Execute; override;
end;
var 섹션 (모듈)
WarframeEventList: TWarframeEventList;
구현 섹션 :
procedure TForm1.TimerUpdateEventsTimer(Sender: TObject);
begin
UpdateFromTwitterThread:=TUpdateFromTwitterThread.Create(True);
UpdateFromTwitterThread.TwitterURL:=form2.EditAlertsURL.Text;
UpdateFromTwitterThread.Start;
UpdateFromRSSThread:=TUpdateFromRSSThread.Create(True);
UpdateFromRSSThread.RSS_URL:=form2.EditInvansionsURL.Text;
UpdateFromRSSThread.Start;
end;
procedure TUpdateFromTwitterThread.Execute;
var
HTTPClient: TIdHTTP;
IOHandler: TIdSSLIOHandlerSocketOpenSSL;
S, S2: String;
i, l: Integer;
NewAlertDate: TDateTime;
ErrorLogFile: TextFile;
begin
HTTPClient:=TIdHTTP.Create(nil);
IOHandler:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
try
HTTPClient.IOHandler:=IOHandler;
HTTPClient.HandleRedirects:=True;
S:=HTTPClient.Get(self.TwitterURL);
except
Assign(ErrorLogFile, AppPath+'Error.log');
if not(FileExists(AppPath+'Error.log')) then
Rewrite(ErrorLogFile);
Append(ErrorLogFile);
Writeln(ErrorLogFile, DateTimeToStr(Now)+' '+LS_ErrorConnection+' '+self.TwitterURL+'; Error code: '+IntToStr(HTTPClient.ResponseCode));
Close(ErrorLogFile);
self.Terminate;
HTTPClient.Free;
IOHandler.Free;
end;
finally
HTTPClient.Free;
IOHandler.Free;
end;
if Application.Terminated or self.Terminated then exit;
S:=copy(S, pos('<b>WarframeAlerts</b></span>', S), Length(S)-pos('<b>WarframeAlerts</b></span>', S));
while pos('tweet-timestamp js-permalink js-nav', S)>0 do begin
S:=copy(S, pos('tweet-timestamp js-permalink js-nav', S)+35, Length(S)-pos('tweet-timestamp js-permalink js-nav', S)-35);
S2:=copy(S, pos('data-time="', S)+11, Length(S)-pos('data-time="', S)-11);
NewAlertDate:=StrToInt(copy(S2, 1, pos('"', S2)-1));
S2:=copy(S, pos('<p class="js-tweet-text tweet-text">', S)+36, pos('</p>', S)-pos('<p class="js-tweet-text tweet-text">', S)-36);
for i:= 0 to WarframeEventList.WarframeEventCount-1 do
if (WarframeEventList.WarframeEvent[i].EventDate=NewAlertDate) and (WarframeEventList.WarframeEvent[i].Planet=copy(S2, 1, pos(')', S2))) then
NewAlertDate:=0;
if NewAlertDate=0 then continue;
Inc(WarframeEventList.WarframeEventCount);
SetLength(WarframeEventList.WarframeEvent, WarframeEventList.WarframeEventCount);
for i:= 0 to WarframeEventList.WarframeEventCount-2 do begin
if WarframeEventList.WarframeEvent[i].EventDate>NewAlertDate then begin
for l:=WarframeEventList.WarframeEventCount-1 downto i+1 do
WarframeEventList.WarframeEvent[l]:=WarframeEventList.WarframeEvent[l-1];
Break;
end;
end;
if i<=WarframeEventList.NotifyEvent.ID then Inc(WarframeEventList.NotifyEvent.ID);
WarframeEventList.WarframeEvent[i].GUID:='';
WarframeEventList.WarframeEvent[i].ItemIndex:=-2;
WarframeEventList.WarframeEvent[i].EventType:=1;
WarframeEventList.WarframeEvent[i].Planet:=copy(S2, 1, pos(')', S2));
S2:=copy(S2, Length(WarframeEventList.WarframeEvent[i].Planet)+3, Length(S2)-Length(WarframeEventList.WarframeEvent[i].Planet));
WarframeEventList.WarframeEvent[i].Mission:=copy(S2, 1, pos(' -', S2)-1);
WarframeEventList.WarframeEvent[i].EventDate:=NewAlertDate;
S2:=copy(S2, Length(WarframeEventList.WarframeEvent[i].Mission)+4, Length(S2)-Length(WarframeEventList.WarframeEvent[i].Mission));
WarframeEventList.WarframeEvent[i].Time:=StrToInt(copy(S2, 1, pos('m', S2)-1))-1;
S2:=copy(S2, pos('-', S2)+2, Length(S2)-pos('-', S2));
WarframeEventList.WarframeEvent[i].RewardCredits:=StrToInt(copy(S2, 1, pos('cr', S2)-1));
WarframeEventList.WarframeEvent[i].RewardOther:=copy(S2, pos('cr', S2)+5, Length(S2)-pos('cr', S2));
WarframeEventList.WarframeEvent[i].RewardOtherAmount:=1;
WarframeEventList.WarframeEvent[i].Notified:=False;
WarframeEventList.WarframeEvent[i].Hidden:=False;
end;
self.Free;
end;
procedure TUpdateFromRSSThread.Execute;
var
HTTPClient: TIdHTTP;
IOHandler: TIdSSLIOHandlerSocketOpenSSL;
S, S2, S3: String;
i: Integer;
NewEventType: Byte;
ErrorLogFile: TextFile;
begin
HTTPClient:=TIdHTTP.Create(nil);
IOHandler:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
try
HTTPClient.IOHandler:=IOHandler;
HTTPClient.HandleRedirects:=True;
S:=HTTPClient.Get(self.RSS_URL);
except
Assign(ErrorLogFile, AppPath+'Error.log');
if not(FileExists(AppPath+'Error.log')) then
Rewrite(ErrorLogFile);
Append(ErrorLogFile);
Writeln(ErrorLogFile, DateTimeToStr(Now)+' '+LS_ErrorConnection+' '+self.RSS_URL+'; Error code: '+IntToStr(HTTPClient.ResponseCode));
Close(ErrorLogFile);
self.Terminate;
HTTPClient.Free;
IOHandler.Free;
end;
finally
HTTPClient.Free;
IOHandler.Free;
end;
if Application.Terminated or self.Terminated then exit;
for i:= 0 to WarframeEventList.WarframeEventCount-1 do
if (WarframeEventList.WarframeEvent[i].EventType=2) or (WarframeEventList.WarframeEvent[i].EventType=3) then
WarframeEventList.WarframeEvent[i].Time:=0;
while pos('<item>', S)>0 do begin
S:=copy(S, pos('<item>', S)+6, Length(S)-pos('<item>', S)-6);
S2:=LowerCase(copy(S, pos('<author>', S)+8, pos('</author>', S)-pos('<author>', S)-8));
NewEventType:=0;
if S2='alert' then
NewEventType:=1;
if S2='invasion' then
NewEventType:=2;
if S2='outbreak' then
NewEventType:=3;
if NewEventType=1 then
Continue;
S2:=LowerCase(copy(S, pos('<guid>', S)+6, pos('</guid>', S)-pos('<guid>', S)-6));
for i:= 0 to WarframeEventList.WarframeEventCount-1 do
if ((WarframeEventList.WarframeEvent[i].EventType=2) or (WarframeEventList.WarframeEvent[i].EventType=3)) and (WarframeEventList.WarframeEvent[i].GUID=S2) then begin
WarframeEventList.WarframeEvent[i].Time:=1;
NewEventType:=255;
end;
if NewEventType=255 then
Continue;
Inc(WarframeEventList.WarframeEventCount);
SetLength(WarframeEventList.WarframeEvent, WarframeEventList.WarframeEventCount);
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].ItemIndex:=-2;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].GUID:=S2;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].EventType:=NewEventType;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].Time:=1;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOther:='';
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOtherAmount:=0;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardCredits:=0;
S2:=copy(S, pos('<title>', S)+7, pos('</title>', S)-pos('<title>', S)-7);
if NewEventType=2 then begin
S2:=Copy(S2, 1, pos(' - ', S2)-1);
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOther:=S2;
S3:=Copy(S2, 1, pos('VS.', S2)-1);
S3:=Copy(S3, pos('(', S3), Length(S3)-pos('(', S3)+1);
if pos('x ', S3)>0 then
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOtherAmount:=StrToInt(copy(S3, 2, pos('x ', S3)-2));
if pos('K)', S3)>0 then
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardCredits:=StrToInt(copy(S3, 2, pos('K)', S3)-2))*1000;
S3:=Copy(S2, pos('VS.', S2)+4, Length(S2)-pos('VS.', S2)-3);
S3:=Copy(S3, pos('(', S3), Length(S3)-pos('(', S3)+1);
if pos('x ', S3)>0 then
if WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOtherAmount<StrToInt(copy(S3, 2, pos('x ', S3)-2)) then
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOtherAmount:=StrToInt(copy(S3, 2, pos('x ', S3)-2));
if pos('K)', S3)>0 then
if WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardCredits<StrToInt(copy(S3, 2, pos('K)', S3)-2))*1000 then
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardCredits:=StrToInt(copy(S3, 2, pos('K)', S3)-2))*1000;
end;
if NewEventType=3 then begin
S2:=Copy(S2, 1, pos(' - ', S2)-1);
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOther:='';
if pos('x ', S2)>0 then begin
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOtherAmount:=StrToInt(copy(S2, 1, pos('x ', S2)-1));
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardOther:=S2;
end;
if copy(S2, Length(S2), 1)='K' then
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].RewardCredits:=StrToInt(copy(S2, 1, Length(S2)-1))*1000;
S2:=copy(S2, 1, Length(S2)-1);
end;
S2:=copy(S, pos('<title>', S)+7, pos('</title>', S)-pos('<title>', S)-7);
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].Planet:=Copy(S2, pos(' - ', S2)+3, Length(S2)-pos(' - ', S2));
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].Mission:=copy(S, pos('<author>', S)+8, pos('</author>', S)-pos('<author>', S)-8);
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].Notified:=False;
WarframeEventList.WarframeEvent[WarframeEventList.WarframeEventCount-1].Hidden:=False;
end;
self.Free;
end;
질문은 다음과 같습니다.
1) 매분마다 쓰레드를 파괴 / 다시 생성하지 않고 재사용 할 수있는 방법이 있습니까? 말할 필요도없이 이로 인해 메모리 조각화가 발생하고 프로그램이 하루 종일 중단없이 작업을 마치면 부풀어 오르기 시작합니다. 여기에 적용 할 수 없기 때문에 루프 스레드를 만드는 방법을 묻지 않습니다.
2) 스레드를 해제 할 적절한시기는 언제입니까? 작업을 완료하기 전에 또는 타이머 핸들러 (1 분마다 실행되는 핸들러)에서 생성하기 전에 해제해야합니까? 아니면 실행이 완료된 후 스레드 자살이 발생합니까?
3) 만들까
HTTPClient: TIdHTTP;
IOHandler: TIdSSLIOHandlerSocketOpenSSL;
매분 파괴 / 재생성을 피하기위한 외부 (전역) 객체?
4) 응용 프로그램을 닫으려고 할 때 스레드가 활성 상태이면 교착 상태가됩니다. 작업을 완료하지 않았거나 분리하지 않은 경우에도 스레드를 종료 할 수있는 방법이 있습니까?
여기에서 많은 질문을 한 다음 많은 양의 코드를 추가했습니다. 코드가 매우 심하게 손상되었습니다. 나는 볼 수있다 :
Self.Free
내부에서 잘못된 호출 Execute
입니다. 그것은 단순히 잘못된 것입니다. FreeOnTerminate
자체 파괴 스레드를 원하는 경우 사용해야합니다 .HTTPClient
와 IOHandler
예외의 경우를.코드에 다른 많은 오류가 있다고 확신합니다.
그러나 나는 그것에 들어가고 싶지 않습니다. 그리고 저는 여러분이 직접 질문 한 네 가지 질문을 모두 다루고 싶지 않습니다. 나는 오직 한 사람으로 만 제한 할 것입니다. 그것을 처리하면 다른 모든 문제가 사라집니다.
매분 스레드를 파괴 / 다시 생성하지 않고 스레드를 재사용 할 수있는 방법이 있습니까?
댓글에서 다음과 같이 말합니다.
예외 후 해제하지 않고
Start
1 분마다 전화하면 어떻게 되나요?
이것은 당신이 가진 근본적인 오해를 나타내는 것 같습니다. 스레드의 코드는 단일 함수 호출에 불과합니다. TThread
해당 기능 의 경우 Execute
. 스레드가 시작되면 Execute
이 호출됩니다. 때 Execute
반환, 해당 스레드의 수명이 끝났습니다. Execute
돌아온 후에 는 다시 시작할 수 없습니다 .
이것이 의미하는 바는 단일 스레드가 단일 작업을 여러 번 반복하도록하려면 Execute
메서드 내부에 루프를 구현해야한다는 것 입니다.
또한 다음과 같이 진술합니다.
여기에 적용 할 수 없기 때문에 루프 스레드를 만드는 방법을 묻지 않습니다.
죄송 합니다만, 틀 렸습니다. 스레드가 작업을 여러 번 수행하도록 만드는 방법은 루핑입니다.
더 일반적으로 나는 당신이 더 높은 수준의 병렬 라이브러리를 이용함으로써 잘 봉사 할 것이라고 생각합니다. 가능한 가장 좋은 것은 OTL입니다.
그 조언을 받아들이고 싶지 않다면 프로그램을 구성하는 방법은 다음과 같습니다.
while not Terminated
루프입니다 Execute
.Terminate
두 스레드에 대한 마스터 스레드 호출을 종료하려면 취소 이벤트를 설정 Free
하고 두 스레드를 호출 합니다. 그런 다음 응용 프로그램을 종료해도 안전합니다.이와 같이 프로그램을 설계하면 다른 모든 질문은 사라집니다. 프로그램의 전체 수명 동안 두 개의 스레드 만 만듭니다. 그것은 질문 1, 2 및 4를 다룹니다. 질문 3의 경우, 이러한 객체를 지역 변수로 유지합니다. 스레드에 로컬이며 Execute
. 또는 더 나은 방법은 Execute
호출 하는 도우미 메서드의 로컬입니다 . 당신의 Execute
방법은 매우 큽니다.
이것과는 별도로 목록의 데이터 경쟁입니다. 이 문제를 해결하는 방법에 대한 자세한 조언을 드릴 수 없습니다. 분명히 일부 직렬화가 필요합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다