스레드를 해제하고 재사용하는 적절한 방법

Sonic Son '편집

저는 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자체 파괴 스레드를 원하는 경우 사용해야합니다 .
  • 당신은 이중 무료로 가지고 HTTPClientIOHandler예외의 경우를.
  • 이 두 스레드에서 변경하는 위험한 데이터 경쟁이 목록에있는 것으로 보입니다.

코드에 다른 많은 오류가 있다고 확신합니다.

그러나 나는 그것에 들어가고 싶지 않습니다. 그리고 저는 여러분이 직접 질문 한 네 가지 질문을 모두 다루고 싶지 않습니다. 나는 오직 한 사람으로 만 제한 할 것입니다. 그것을 처리하면 다른 모든 문제가 사라집니다.

매분 스레드를 파괴 / 다시 생성하지 않고 스레드를 재사용 할 수있는 방법이 있습니까?

댓글에서 다음과 같이 말합니다.

예외 후 해제하지 않고 Start1 분마다 전화하면 어떻게 되나요?

이것은 당신이 가진 근본적인 오해를 나타내는 것 같습니다. 스레드의 코드는 단일 함수 호출에 불과합니다. TThread해당 기능 의 경우 Execute. 스레드가 시작되면 Execute이 호출됩니다. Execute반환, 해당 스레드의 수명이 끝났습니다. Execute돌아온 후에 다시 시작할 수 없습니다 .

이것이 의미하는 바는 단일 스레드가 단일 작업을 여러 번 반복하도록하려면 Execute메서드 내부에 루프를 구현해야한다는 것 입니다.

또한 다음과 같이 진술합니다.

여기에 적용 할 수 없기 때문에 루프 스레드를 만드는 방법을 묻지 않습니다.

죄송 합니다만, 틀 렸습니다. 스레드가 작업을 여러 번 수행하도록 만드는 방법은 루핑입니다.


더 일반적으로 나는 당신이 더 높은 수준의 병렬 라이브러리를 이용함으로써 잘 봉사 할 것이라고 생각합니다. 가능한 가장 좋은 것은 OTL입니다.

그 조언을 받아들이고 싶지 않다면 프로그램을 구성하는 방법은 다음과 같습니다.

  1. 타이머를 제거하십시오.
  2. 두 개의 스레드를 만들고 종료 될 때까지 무기한 반복되도록합니다. 이것은 메서드 의 표준 while not Terminated루프입니다 Execute.
  3. 스레드가 루프의 각 반복에서 작업을 수행하도록합니다.
  4. 작업이 끝나면 1 분 (또는 오래) 기다려야합니다. 지정된 시간 제한 동안 이벤트를 기다리면됩니다.
  5. 이 이벤트는 종료 할 때 스레드를 취소하기 위해 이벤트를 사용하는 제어 마스터 스레드에 알려질 수 있습니다.
  6. 따라서 Terminate두 스레드에 대한 마스터 스레드 호출을 종료하려면 취소 이벤트를 설정 Free하고 두 스레드를 호출 합니다. 그런 다음 응용 프로그램을 종료해도 안전합니다.

이와 같이 프로그램을 설계하면 다른 모든 질문은 사라집니다. 프로그램의 전체 수명 동안 두 개의 스레드 만 만듭니다. 그것은 질문 1, 2 및 4를 다룹니다. 질문 3의 경우, 이러한 객체를 지역 변수로 유지합니다. 스레드에 로컬이며 Execute. 또는 더 나은 방법은 Execute호출 하는 도우미 메서드의 로컬입니다 . 당신의 Execute방법은 매우 큽니다.

이것과는 별도로 목록의 데이터 경쟁입니다. 이 문제를 해결하는 방법에 대한 자세한 조언을 드릴 수 없습니다. 분명히 일부 직렬화가 필요합니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

PostgreSQL: '고아' 레코드를 삭제하는 적절한 방법

작업자 스레드를 종료하는 적절한 방법

기존 유형 정의를 재사용하는 적절한 방법

스토리 보드를 사용할 때 모달을 해제하는 적절한 방법은 무엇입니까?

스레딩 오류를 피하기 위해 invoke를 사용하는 적절한 방법은 무엇입니까?

HOC를 사용하고 적절하게 재구성하는 방법

레코드를 추가하고 room 및 mvvm을 사용하여 활동을 알리는 적절한 방법

알림으로 mp3 사운드를 재생하는 적절한 방법

PHP와 strcmp 함수를 사용하는 적절한 방법

파이썬에서 ** kwargs를 사용하는 적절한 방법

React hooks + WebSockets를 사용하는 적절한 방법

CUDA 스레드를 재활용 / 재사용하는 방법

TableViewCell의 SegmentedControl-셀을 재사용하는 적절한 방법

jboss 6.3.0 : 안정감을 제거하고 저지를 사용하는 적절한 방법

여러 갈래 스레드를 만드는 적절한 방법

이에 대한 적절한 유효성 검사를 수행하고 포커스를 설정 한 다음 양식을 제출해야하는 방법

복잡한 문제에 대해 위치 인수를 적절하게 사용하는 방법

현재 막대를 감지하는 적절한 방법?

라우터 콘센트를 적절한 방법으로 사용하는 방법

PHP를 사용하여 적절한 배열 형식을 만드는 방법

Powershell을 사용하여 적절한 do-while 루프를 만드는 방법

Groovy :이 클래스를 생성 / 사용하는 적절한 방법

C # 스트림에서 DisposeAsync를 사용하는 적절한 방법

Perl 스크립트 내에서 Ack를 사용하는 적절한 방법?

Vuejs-요소를 복제하고 DOM에 추가하는 적절한 방법

Realm에서 객체를 적절하고 스레드로부터 안전하게 삭제하는 방법

Entity Framework 컨텍스트에서 모든 레코드를 삭제하고 다시 만드는 적절한 방법은 무엇입니까?

탈출하는 적절한 방법 | HTML 엔티티를 사용하는 문자

스레드를 죽이는 적절한 방법

TOP 리스트

  1. 1

    셀레늄의 모델 대화 상자에서 텍스트를 추출하는 방법은 무엇입니까?

  2. 2

    Blazor 0.9.0 및 ASP.NET Core 3 미리보기 4를 사용한 JWT 인증

  3. 3

    openCV python을 사용하여 텍스트 문서에서 워터 마크를 제거하는 방법은 무엇입니까?

  4. 4

    C # 16 진수 값 0x12는 잘못된 문자입니다.

  5. 5

    Excel : 합계가 N보다 크거나 같은 상위 값 찾기

  6. 6

    오류 : MSB4803 : MSBuild의 .NET Core 버전에서 "ResolveComReference"작업이 지원되지 않습니다.

  7. 7

    R에서 Excel로 내보낼 때 CET / CEST 시간 이동이 삭제됨

  8. 8

    node.js + postgres : "$ 1"또는 그 근처에서 구문 오류

  9. 9

    확대 후 하이 차트에서 Y 축이 잘못 정렬 됨

  10. 10

    EPPlus에서 행 높이를 설정할 때 이상한 동작

  11. 11

    Ionic 2 로더가 적시에 표시되지 않음

  12. 12

    MS Access 부분 일치 2 테이블

  13. 13

    EPPlus에서 병합 된 셀의 행 높이 자동 맞춤

  14. 14

    ExecuteNonQuery- 연결 속성이 초기화되지 않았습니다.

  15. 15

    ResponseEntity를 사용하고 InputStream이 닫히는 지 확인하는 적절한 스트리밍 방법

  16. 16

    PrematureCloseException : 연결이 너무 일찍 닫혔습니다.

  17. 17

    오류 : "const wchar_t *"유형의 인수가 "WCHAR *"유형의 매개 변수와 호환되지 않습니다.

  18. 18

    Java에서 이미지를 2 색으로 변환

  19. 19

    overflow-y를 사용할 때 스크롤 버벅 거림 줄이기 : scroll;

  20. 20

    Java에서 Apache POI를 사용하여 테이블 크기 및 간격을 단어로 설정하는 방법

  21. 21

    Android Kotlin은 다른 활동에서 함수를 호출합니다.

뜨겁다태그

보관