델파이의 스레드 클래스-(1)
델파이의 스레드 클래스-(1) 랩터 (원본 작품)
키워드 ThreadEventCriticalSectionSynchronize
델파이의 스레드 클래스
랩터스 [Mentalstudio]
http://mental.mentsu.com
(하나)
Delphi에는 Multi-Shread 프로그래밍을 구현하는 데 사용되는 스레드 클래스 Tthread가 있으며, 기본적으로 Tthread 클래스의 여러 회원에 대한 간단한 소개를 제공 한 다음의 구현 및 사용법을 설명합니다. 동기화가 완료되었습니다. 그러나 이것은 다중 스레드 프로그래밍의 전체가 아닙니다.
스레드는 본질적으로 프로세스에서 동시에 실행되는 코드 조각입니다. 프로세스에는 적어도 하나의 스레드, 소위 기본 스레드가 있습니다. 여러 자식 실이있을 수도 있습니다. 프로세스에서 둘 이상의 스레드를 사용하면 "멀티 스레딩"이라고합니다.
그렇다면 소위 "코드 조각"은 어떻게 정의됩니까? 실제로는 기능 또는 프로세스입니다 (델파이의 경우).
Windows API를 사용하여 스레드를 생성하는 경우 CreateThread라는 API 함수를 통해 구현됩니다.
HandleCreateThread (
lpsecurity_attributeslpthreadattributes,
dworddwstacksize,
lpthread_start_routinelpstartAddress,
lpvoidlpparameter,
dworddwcreationflags,
lpdwordlpthreadid
);
그들의 매개 변수는 이름, 즉 스레드 속성 (NT에서 스레드 보안 속성을 설정하는 데 사용), 스택 크기, 시작 주소, 매개 변수 및 생성 플래그 (생성 시간에 스레드를 설정하는 데 사용됨)에 언급되어 있습니다. , 스레드 ID를하고 마지막으로 스레드 핸들을 반환합니다. 시작 주소는 스레드 함수의 입구이며 스레드 기능이 끝날 때까지 스레드가 끝납니다.
전체 스레드의 실행 프로세스는 다음과 같습니다.
CreateThread 매개 변수는 많고 Windows API이므로 일반 스레딩 기능은 Cruntimelibrary에서 제공됩니다 (이론적으로는 스레드를 지원하는 모든 OS에서 사용할 수 있음).
unsignedlong_beginthread (void (_userentry*__ start) (void*), unsigned__stkize, void*__ arg);
Delphi는 또한 동일한 기능을 가진 유사한 기능을 제공합니다.
FunctionBeginThread (SecurityAttributes; Pointer; Stacksize : longword; ThreadFunc : TthreadFunc; 매개 변수 : 포인터; CreationFlags : Longword; VarthreadId : Longword) : 정수;
이 세 가지 함수의 기능은 기본적으로 동일합니다. 스레드 함수와 일반 기능의 가장 큰 차이점은 스레드 기능이 시작 되 자마자이 세 스레드가 함수를 시작하고 기본 스레드가 계속 실행되는 반면 스레드 기능은 독립 스레드에서 실행된다는 것입니다 실행하는 데 걸리고 반환 할 때 메인 스레드가 신경 쓰지 않거나 알지 못합니다.
정상적인 상황에서 스레드 함수가 반환 된 후 스레드가 종료됩니다. 그러나 다른 방법이 있습니다.
Windows API :
voidexitthread (dworddwexitcode);
Cruntimelibrary :
void_endthread (void);
delphiruntimelibrary :
ProcedureEndThread (ExitCode : Integer);
필요한 스레드 데이터 (상태/속성 등)를 기록하기 위해 OS는 스레드의 내부 객체를 생성하므로 Windows의 핸들은이 내부 객체의 핸들이므로 객체를 해제해야합니다. 스레드가 끝납니다.
API 또는 RTL (runtimelibrary)을 사용하여 멀티 스레딩 프로그래밍을 쉽게 수행 할 수 있지만, 더 자세한 처리는 여전히 필요합니다. 델파이는 VCL 스레드 클래스 인 클래스 장치에서 더 나은 스레드 패키지를 만들었습니다.
이 클래스를 사용하는 것은 매우 간단합니다. 대부분의 델파이 책은 기본 사용법이 다음과 같습니다. 먼저 tthread (tthread는 추상 클래스이고 인스턴스를 생성 할 수 없기 때문에). 이것은 스레드에서 실행 된 코드 부분 인 스레드 기능입니다. 이에 대한 구체적인 자세한 내용은 여기에서 반복하지 않으며 관련 책을 참조하십시오.
이 기사의 다음으로, 우리는 Tthread 클래스가 스레드를 어떻게 캡슐화하는지, 즉 Tthread 클래스의 구현에 대한 심층적 인 연구를 수행 할 것입니다. 당신이 그것을 정말로 이해한다면 그것을 사용하는 것이 더 낫기 때문입니다.
아래는 Delphi7의 Tthread 클래스 선언입니다 (이 기사는 Windows 플랫폼의 구현에 대해서만 설명하므로 Linux 플랫폼 부분에 대한 모든 코드가 제거됩니다).
tthread = 클래스
사적인
Fhandle : Thandle;
fthreadid : thandle;
fcreatesuspended : 부울;
ferminated : 부울;
fsuspended : 부울;
ffreeonterminate : 부울;
ffinished : 부울;
FreturnValue : 정수;
fonterminate : tnotifyevent;
fsynchronize : tsynchronizerecord;
ffatalexception : tobject;
ProcessEcallonterminate;
ClassProceduresynchronize (Asyncrec : PSYNCHRONIZERECORD);
FunctionGetPriority : TTHREADPRIORITY;
ProcessETPRIORITY (값 : TTHREADPRIORITY);
ProcessEsSpended (값 : 부울);
보호
ProcessEcheckthreadError (errcode : integer); 오버로드;
ProcessEcheckthreadError (성공 : 부울); 과부하;
ProcessErminate; 가상;
ProcessExecute; 가상; 초록;
Proceduresynchronize (메소드 : tthreadmethod); 과부하;
PropertyReturnValue : IntegerReadFreturnValueWRiteFreturnValue;
Property Terniminated : BooleanReadfTerminated;
공공의
ConstructorCreate (CreateSuspended : 부울);
Destructordestroy; 재정의;
이후 절차 건설; 재정의;
Processeresume;
절차 보조;
절차가 결정됩니다.
FunctionWaitfor : Longword;
classproceduresynchronize (Athread : tthread; amethod : tthreadmethod); 과부하;
ClassProcedUreStaticSynchronize (ATHREAD : TTHREAD; AMETHOD : TTHREADMETHOD);
PropertyFatalException : TobjectReadffatalexception;
PropertyFreeOnterminate : booleanReadfReeOnterminateWriteFreeOnterminate;
PropertyHandle : ThandlerEadfhandle;
PropertyPriority : tthreadPriorityReadGetPriorityWritesEtPriority;
PropertySuspended : booleanreadfsuspendedWritesEsSuspended;
PropertyThreadId : Thandlereadfthreadid;
PropertyOnterminate : tnotifyEventReadFonterminateWriteFonterminate;
끝;
Tthread 클래스는 Delphi RTL에서 비교적 간단한 클래스이며, 클래스 멤버가 많지 않으며 클래스 속성은 매우 간단하고 명확합니다.
(계속하려면)
델파이의 스레드 클래스-(2)
델파이의 스레드 클래스-(2) 랩터 (원본 작품)
키워드 ThreadEventCriticalSectionSynchronize
델파이의 스레드 클래스
랩터스 [Mentalstudio]
http://mental.mentsu.com
둘
첫 번째는 생성자입니다.
ConstructortThread.create (CreateSuspended : Boolean);
시작하다
상속 된 생성;
addthread;
fsuspended : = createSuspended;
fcreatesuspended : = createSuspended;
fhandle : = beginthread (nil, 0,@strookproc, pointer (self), create_suspended, fthreadid);
iffhandle = 0then
raseEthread.createresfmt (@sthreadrecreateerror, [syserrormessage (getLasterror)]);
끝;
이 생성자에는 코드가 많지 않지만 스레드가 여기에서 생성되기 때문에 가장 중요한 멤버로 간주 될 수 있습니다.
상속 된 것을 통해 Tobject.create를 호출 한 후 첫 번째 문장은 프로세스를 호출하는 것입니다. AddThread, 소스 코드는 다음과 같습니다.
ProcessEaddThread;
시작하다
interlockedIncrement (ThreadCount);
끝;
해당 removeThread도 있습니다.
ProcesserEmovethread;
시작하다
인터록드 드레임 (ThreadCount);
끝;
기능은 매우 간단합니다. 이는 전역 변수를 추가하거나 줄임으로써 프로세스의 스레드 수를 계산하는 것입니다. 그러나 여기에 일반적으로 사용되는 Inc/DEC 프로세스는 일반적으로 사용되는 Inc/DEC 프로세스가 아니지만, 인터록드 크레멘트/인터록드 데크 프로세스가 사용됩니다. 그러나 그들 사이에는 가장 큰 차이점이 있습니다. 즉, 멀티 스레딩에서 실행 결과가 올바른지 확인할 수 있지만 INC/DEC는 할 수 없습니다. 또는 운영 체제 이론 측면에서 이것은 한 쌍의 "원시"작업입니다.
두 가지의 구현 세부 사항의 차이를 설명하기 위해 추가를 예로 들어보십시오.
일반적으로 메모리 데이터에 하나를 추가하는 작업을 분해 한 후 세 단계가 있습니다.
1. 메모리에서 데이터를 읽습니다
2. 하나의 데이터를 추가하십시오
3. 메모리에 저장하십시오
이제 2 스레드 애플리케이션에서 INC를 사용하여 하나를 추가하는 작업이 발생할 수 있다고 가정합니다.
1. 스레드 a는 메모리에서 데이터를 읽습니다 (3이라고 가정)
2. 스레드 B는 메모리에서 데이터를 읽습니다 (또한 3)
3. 스레드 a는 데이터를 데이터에 추가합니다 (이제 4)
4. 스레드 B는 데이터에 하나를 추가합니다 (이제 4)
5. A를 메모리에 스토리지 (메모리의 데이터는 이제 4).
6. 스레드 B는 또한 데이터를 메모리에 저장합니다 (메모리의 데이터는 여전히 4이지만 두 스레드는 하나를 추가하여 5이어야하므로 오류 결과가 여기에 나타납니다).
소위 "원시"는 무질서 수술이기 때문에 인터 로크 크레멘트 프로세스에는 문제가 없다. 즉, 운영 체제는 "원시"가 실행되기 전에 스레드 스위칭이 수행되지 않도록 할 수 있기 때문이다. 따라서 위의 예에서는 스레드 A가 메모리에 데이터 저장을 마친 후에 만 스레드 B가 숫자를 가져오고 하나의 작업을 추가하여 멀티 스레딩 상황에서도 결과가 정확히 올바른지 확인할 수 있습니다.
이전 예는 또한 "스레드 액세스 충돌"의 상황을 보여 주므로 스레드는 "동기화"가 필요합니다.
동기화에 관해 말하면, 산만 함이 있습니다 : 캐나다 워털루 대학교의 교수 인 Li Ming은 한 번 "스레드 동기화"에서 "동기화"로 동기화 된 단어의 번역에 대한 이의를 제기했습니다 매우 합리적입니다. 중국어에서 "동기화"는 "동시에 발생"을 의미하는 반면 "스레드 동기화"는 그러한 "동시에 발생"을 피하기위한 것입니다. 영어에서 Synchronize는 두 가지 의미를 갖습니다. 하나는 전통적인 의미 (Tooccuratthesametime)의 동기화이고 다른 하나는 "조정"입니다. "스레드 동기화"에 동기화 된 단어는 후자의 의미, 즉 "여러 스레드가 동일한 데이터에 액세스 할 때 오류를 피하기 위해 후자의 의미를 지칭해야합니다. 그러나 IT 산업에서 정확하게 번역되지 않은이 기사가 여전히 사용될 것입니다. 명확히해야합니다.
나는 멀리 갈 것이고, 나는 가장 중요한 문장의 생성자로 돌아갈 것이다.
fhandle : = beginthread (nil, 0,@strookproc, pointer (self), create_suspended, fthreadid);
여기에서 우리는 위에서 언급 한 delphirtl function을 사용합니다. 많은 매개 변수가 있습니다. 세 번째 매개 변수는 위에서 언급 한 스레드 함수, 즉 스레드에서 실행 된 코드 부분입니다. 네 번째 매개 변수는 스레드 함수로 전달되는 매개 변수입니다. 여기에 생성 된 스레드 객체 (즉, self)가 있습니다. 다른 매개 변수 중에서, 다섯 번째는 생성 후 스레드를 중단하고 즉시 실행하지 않도록 스레드를 설정하는 데 사용됩니다 (스레드를 시작하는 작업은 CreateSuspended 플래그를 기반으로 애프터 구성에서 결정됩니다). 여섯 번째는 스레드 ID를 반환하는 것입니다.
이제 tthread : thread function streadproc의 핵심을 살펴 보겠습니다. 흥미롭게도,이 스레드 클래스의 핵심은 스레드의 구성원이 아니라 글로벌 기능입니다 (Beginthread 프로세스의 매개 변수 규칙은 글로벌 함수 만 사용할 수 있기 때문입니다). 코드는 다음과 같습니다.
functionthreadproc (스레드 : tthread) : 정수;
var
Freethread : 부울;
시작하다
노력하다
ifnotthread.meratedthen
노력하다
Thread.Execute;
제외하고
thread.ffatalexception : = arceeexceptionObject;
끝;
마지막으로
Freethread : = thread.freeonterminate;
결과 : = thread.freturnValue;
thread.doterminate;
Thread.finished : = true;
신호 체증;
iffreethreadthenthread.free;
endthread (결과);
끝;
끝;
코드는 많지 않지만이 코드는 실제로 스레드에서 실행되는 코드이기 때문에 전체 tthread의 가장 중요한 부분입니다. 다음은 코드에 대한 라인별 설명입니다.
먼저, 스레드 클래스의 종료 플래그가 종료되지 않은 경우, TTHREAD가 추상 클래스이고 실행 메소드가 추상적 인 메소드이기 때문에 스레드 클래스의 실행 메소드가 호출됩니다. 기본적으로 파생 클래스에서 실행 코드를 실행하고 있습니다.
따라서 Execute는 스레드 클래스의 스레드 기능입니다.
Execute에서 예외가 발생하면 Exception Object는 AcquiReexceptionObject를 통해 얻어지고 스레드 클래스의 FFATALEXCeption 멤버에 저장됩니다.
마지막으로 스레드가 끝나기 전에 완료된 마무리 작업이 있습니다. 로컬 변수 Freethread는 스레드 클래스의 FreeOnterminated 속성 설정을 기록한 다음 스레드 리턴 값을 스레드 클래스 리턴 값 속성의 값으로 설정합니다. 그런 다음 스레드 클래스의 doterminate 메소드를 실행하십시오.
doterminate 방법의 코드는 다음과 같습니다.
ProcessEtThread.Doterminate;
시작하다
ifassigned (fonterminate) thensynchronize (callonterminate);
끝;
매우 간단합니다. Synchronize를 통해 Callonterminate 메소드를 호출하는 것이 매우 간단하며 Callonterminate 메소드의 코드는 다음과 같습니다. 이는 단순히 Onterminate 이벤트를 호출하는 것입니다.
ProcessEtThread.CallOnterminate;
시작하다
Ifassigned (fonterminate) thenfonterminate (self);
끝;
onterminate 이벤트는 동기화로 실행되므로 본질적으로 스레드 코드가 아니라 기본 스레드 코드입니다 (나중에 동기화 분석 참조).
onterminate를 실행 한 후 스레드 클래스의 ffinished 플래그를 true로 설정하십시오.
다음으로 신호 확인 프로세스를 실행하면 코드가 다음과 같습니다.
ProcessIngyncevent;
시작하다
setEvent (syncevent);
끝;
또한 매우 간단합니다. 이벤트 사용과 관련하여 글로벌 이벤트를 설정하는 것이 좋습니다.