Thread class in Delphi
Raptor [Mental Studio] http://eental.mentsu.com
Bis first is the constructor: constructor TThread.Create (CreateSuspended: Boolean); begin inherited Create; AddThread; FSuspended: = CreateSuspended; FCreateSuspended: = CreateSuspended; FHandle: = BeginThread (nil, 0, @ThreadProc, Pointer (Self), Create_suspended, fthreadid; if fhandle = 0 Then Raise Ethread.createresfmt (@SthreadCreateError, [SySerrorMeration (getLastError)]); END; Although this constructor does not have much code, it can be an important member, because thread is It is created here. After calling TObject.Create by Inherited, the first one is a call procedure: AddThread, its source code is as follows: procedure AddThread; begin InterlockedIncrement (ThreadCount); end; also has a corresponding RemoveThread: procedure RemoveThread; begin InterlockedDecrement (ThreadCount); END; their function is simple, is to count the number of threads in the process by adding a global variable. Just here to increase or decrease variables is not commonly used Inc / DEC processes, but use InterlockedIncrement / InterlockedDecrement, which is exactly the same as the variables, and the variables are all or minus one. But they have a biggest difference, that is, InterlockedIncrement / InterlockedDecrement is thread security. That is, they can guarantee the execution result in the multi-thread, and INC / DEC cannot. Or by the term in the operating system theory, this is a pair of "primitives" operations. Take one as an example to illustrate the different details of the two: In general, there are three steps after the operation decomposition of the memory data plus one, read the data 2 from the memory, data plus one 3, deposit memory Now, it is now assumed that in the application of two threads, use INC to add an operation, and thread a read data from memory (assuming 3) 2, thread b reads data from memory (also 3) 3, thread a pair data plus (now 4) 4, thread b add (now 4) 5, thread a deposit data into memory (now data in memory is 4) 6, thread B Also store data into memory (now data in memory is 4, but both threads have added one, should be 5 only, so there is a wrong result) and there is no problem with the interlockincrement process, because The so-called "primitive" is an uninterruptible operation, that is, the operating system guarantees that the thread switching will not be performed before a "primitive" is executed. So in the above example, only when the thread a execution is stored in memory, thread b can start to take a number and add another operation, so that even if it is in multi-thread, the results will certainly is correct.
The previous example also illustrates a situation of "thread access conflicts", which is why the thread needs "synchronize", about this, will also discuss in detail when it is synchronized later. Speaking of synchronization, there is a question: Li Ming, a professor of Canada Waterloo University, has been translated in "Thread Synchronization" in "Thread Synchronization" in "Thread Synchronization", which is actually very reasonable. In Chinese, "synchronization" means "happening simultaneously", and "thread synchronization" purpose is to avoid this "simultaneous happening". In English, Synchronize's meaning is two: one is a traditional sense of synchronization (To Occur At the Same Time), the other is "To Operate IN Unison). The word "Thread Synchronization" should refer to it later, ie "guarantees that multiple threads will be harmonized, avoid errors," However, there is still a lot of words like this in the IT industry. Since it is already a customary, this article will continue to use, just explain here, because software development is a meticulous job, which is clear, absolutely It is not ambiguous.
It's far away, go back to Tthread's constructor, the next most important is this: fhandle: = beginthread (nil, 0, @threadproc, pointer (self), create_suspended, fthreadid); here, it used to say Delphi RTL function beginthread, it has many parameters, the key is the third, four or two parameters. The third parameter is the previously mentioned thread function, that is, the code portion executed in the thread. The fourth parameter is the parameter passed to the thread function, where it is created thread object (ie, Self). In other parameters, the fifth is used to set threads to hang after being created, and do not perform immediately (starting the thread is determined in the CreateSusPended flag according to the CREATESUSPENDED flag), the sixth is the return thread ID. Now look at the core of TTHREAD: Thread function threadproc. Interesting is the core of this thread class is not a member of the thread, but a full-time function (because the parameters of the BeginThread process can only use global functions). The following is its code: function ThreadProc (Thread: TThread): Integer; var FreeThread: Boolean; begin try if not Thread.Terminated then try Thread.Execute; except Thread.FFatalException: = AcquireExceptionObject; end; finally FreeThread: = Thread. FFreeOnTerminate; Result: = Thread.FReturnValue; Thread.DoTerminate; Thread.FFinished: = True; SignalSyncEvent; if FreeThread then Thread.Free; EndThread (Result); end; end; although not much code, but it is the whole TThread The most important part, because this code is the code that is really executed in the thread. The following pair of code lines: First determine the TERMINATED flag of the thread class, if not the flag is terminated, then call the thread class's Execute method to execute thread code, because TTHREAD is an abstract class, the Execute method is an abstract method, so essentially It is an Execute code in the derived class. So, Execute is a thread function in the thread class, all of which need to make a thread code, such as preventing access violations. If Execute has exceeded an exception, the exception object is obtained via AcquireExceptionObject and stored in the FFATALEXCEPTION member of the thread class. Finally some of the ends of the thread did before the end of the thread. The local variable Freethread records the setting of the freeOnterminated property of the thread class, and then set the thread return value to the value of the returned value attribute of the thread class. Then execute the thread class Doterminate method.