1. CriticalSection: when a piece of code is put into a critical section, the thread is exclusive when it is executed in the critical section, let other threads that need to execute this code wait; this is similar to the previous Lock and UnLock; The format is as follows: Var
CS: TRTLCriticalSection; {declare a TRTLCriticalSection structure type variable; it should be global}
InitializeCriticalSection (CS); {initialization}
EnterCriticalSection (CS); {start: It's my turn to move other threads away}
LeaveCriticalSection (CS); {end: other threads can come}
DeleteCriticalSection (CS); {Delete: Do not delete it too early}
// You can also use TryEnterCriticalSection to replace EnterCriticalSection.
Delphi encapsulates a TCriticalSection class in the SyncObjs unit. The usage is similar to the second. The waiting function WaitForSingleObject Function WaitForSingleObject (
HHandle: THandle; {handle of the object to wait}
Dwmilliseconds: DWORD {Wait time, in milliseconds}
): DWORD; stdcall; {return value :}
WAIT_OBJECT_0 {waiting}
WAIT_TIMEOUT {Wait a moment (the time you specified), not yet}
WAIT_ABANDONED {It's hard to wait, but people still don't want us to execute it; this is generally a mutex object}
// The second parameter of WaitForSingleObject is generally given to the constant value INFINITE, which indicates that the parameter is always waiting and the parameter is dead.
What is waitforsingleobject waiting? In multithreading, you can wait for the end of another thread to execute your own code. However, you can wait for more than one thread. Here is an example of waiting for the end of another process to run: 3. mutex (mutex object) the mutex object is the system kernel object. Each thread can own it and anyone who owns it can execute it. After the execution is complete, the releasemutex function is used to release the ownership, to be used by other waiting threads. other threads can wait in queue using the waitforsingleobject function (waiting can also be understood as queuing application ). Ar hmutex: thandle; {A Global mutex handle should be declared first}
Createmutex {create a mutex object}
Waitforsingleobject {waiting in queue with the waiting function}
Releasemutex {release ownership}
Closehandle {last released mutex object}
The releasemutex and closehandle parameters are all the handles returned by createmutex. The key is the createmutex function.
Function CreateMutex (
LpMutexAttributes: PSecurityAttributes;
BInitialOwner: BOOL; {whether to allow the creator (in this example, the main thread) to own the mutex object}
LpName: PWideChar {you can give this mutex a name. If you do not want a name, you can assign it to nil}
): THandle;
{
1. The first parameter is mentioned earlier.
2. The second parameter must be False here. If the main thread is mutually exclusive, in theory, it is necessary to wait for other threads to exit the program;
When the value is False, the first thread to be executed will first have a mutex object. Once there are other threads, you must wait.
3. For the third parameter, if a name is given, the function will look for mutex objects with duplicate names from the system. If yes, a handle with the same name will be returned;
If the value is nil, a new mutex object will be created directly. In the next example, a name will be created .}
As the core object of the system, Mutex can be cross-process (the critical section won't work). We can use Mutex to prevent repeated startup of programs. idea: first use OpenMutex to open a Mutex object with a custom name. If it fails to be opened, it indicates that this object did not exist before. If this object was not found before, use CreateMutex to create one immediately, at this time, the program should be started for the first time; when the program is restarted again, the OpenMutex will have the result, and then force the exit. at the end of the program, use CloseHandle to release the Mutex object. Function OpenMutex (
DwDesiredAccess: DWORD; {open permission}
BInheritHandle: BOOL; {can it be inherited by the process created by the current program}
PName: PWideChar {name of the Mutex object}
): THandle; stdcall; {the handle of Mutex is returned successfully; 0 is returned if the operation fails}
Note that the CreateMutex function should have a name, because OpenMutex is required. In addition, the second parameter of CreateMutex is no longer important (both True and False ), it is determined by its name. Var
HMutex: THandle;
Const
NameMutex = 'mymutex ';
Procedure TForm1.FormCreate (Sender: TObject );
Begin
If OpenMutex (MUTEX_ALL_ACCESS, False, NameMutex) <> 0 then
Begin
ShowMessage ('The program started ');
Application. Terminate;
End;
HMutex: = CreateMutex (nil, False, NameMutex );
End;
4. Before semaphore (signal object), there have been two multithread Synchronization Methods: criticalsection (critical section) and mutex (mutex). These two Synchronization Methods are similar, but they have different scopes; the criticalsection is similar to a public restroom with only one squatting position and can only be entered one by one. The mutex (mutex) object is similar to the baton in the relay race. It can only be held by one person at a time. what is semaphore? For example, if you have to go to a bank or buy a ticket at the station, there is only one waiter. No matter how many people are waiting in queue, the business can only come one by one. if a business window is added, how many businesses can be accepted at the same time? This is similar to the semaphore object. semaphore can process several threads simultaneously applied by waiting functions (such as waitforsingleobject. semaphore's working ideas are as follows: 1. First, you must use createsemaphore (Security Settings, initial signal count, total signal count, and signal name) to create a signal object. Parameter 4: Same as mutex, it can have a name or no name. In this example, there is no name (NiL); a name is generally used for cross-process. parameter 3: The total number of signals, which is the maximum processing capacity of semaphore, just like the number of business windows in a bank; parameter 2: initial number of signals, which is like a lot of business windows in a bank, but it may not be possible to open a few, if not open and not the same; parameter 1: Security Settings as before, use the default (nil. 2. To accept the thread of the semaphore service (or called the coordination), you also need to queue for the waiting function (such as waitforsingleobject). 3. When a thread uses a signal, releasesemaphore (signal handle, 1, nil) should be used to give available signals to other threads; parameter 3: generally nil. If a digital pointer is given, it can be accepted until now (Before) the total number of idle signals. Parameter 2: generally 1, indicates adding an available signal. If you want to increase the initial signal for createsemaphore, you can use releasesemaphore.4 and finally as the system kernel object, use closehandle to disable it. in addition, when the total number of semaphore is 1, it is the same as mutex (mutex. VaR
F: Integer; {use this variable to coordinate the output position of each thread}
HSemaphore: THandle; {handle of the signal object}
Function MyThreadFun (p: Pointer): DWORD; stdcall;
Var
I, y: Integer;
Begin
Inc (f );
Y: = 20 * f;
If WaitForSingleObject (hSemaphore, INFINITE) = WAIT_OBJECT_0 then
Begin
For I: = 0 to 1000 do
Begin
Form1.Canvas. Lock;
Form1.Canvas. TextOut (20, y, IntToStr (I ));
Form1.Canvas. Unlock;
Sleep (1); {to avoid busy Canvas}
End;
End;
ReleaseSemaphore (hSemaphore, 1, nil );
Result: = 0;
End;
Procedure TForm1.Button1Click (Sender: TObject );
Var
ThreadID: DWORD;
Begin
{I do not know if I have created a Semaphore object before. If yes, close it first}
CloseHandle (hSemaphore );
{Create Semaphore object}
HSemaphore: = CreateSemaphore (nil, StrToInt (Edit1.Text), 5, nil );
Self. Repaint;
F: = 0;
CreateThread (nil, 0, @ MyThreadFun, nil, 0, ThreadID );
CreateThread (nil, 0, @ MyThreadFun, nil, 0, ThreadID );
CreateThread (nil, 0, @ MyThreadFun, nil, 0, ThreadID );
CreateThread (nil, 0, @ MyThreadFun, nil, 0, ThreadID );
CreateThread (nil, 0, @ MyThreadFun, nil, 0, ThreadID );
End;
Procedure TForm1.FormDestroy (Sender: TObject );
Begin
CloseHandle (hSemaphore );
End;