Some methods about thread synchronization

zhaozj2021-02-16  56

The thread is a relatively independent, scheduled execution unit in the process. An application can have a main thread, a main thread can have multiple sub-threads, and the sub-thread can have its own sub-thread, which constitutes a multi-threaded application. Since multiple threads tend to access the same block memory area, frequent access to this area will increase the probability of generating thread conflicts. Once a conflict is created, the unpredictable result will be made (the value of the common area is unpredictable) The need to process thread synchronization can be seen.

Note: All the code appeared in this article is described in Delphi, the debugging environment is Windows Me, Delphi 6. The Windows API functions involved can get a detailed document from MSDN.

Firstly, an example will lead to the discussion below, this instance does not take any measures to avoid thread conflicts, its main process is: starting the two threads by the main thread to perform frequently read and write the global variables of Letters, then modify The result is displayed in ListBox. Since there is no synchronization of these two threads, threads have generated unpredictable results when modifying Letters. Everyone can look at the results it run, as shown:

The letters of each line in ListBox should be consistent, but the drawing line is different, which is the result of thread conflicts. When two threads accesses the shared memory at the same time, a thread has not completed the memory, and the other thread modified the memory. Since the process of writing is not serialized, this has an invalid result. . Visible thread synchronization importance.

The following is the code of this example

Unit.pas file

Unit unit1;

Interface

Uses

Windows, Messages, Sysutils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, stdctrls;

// Define window classes

Type

TFORM1 = Class (TFORM)

Listbox1: tlistbox;

Listbox2: tlistbox;

Button1: tbutton;

Procedure Button1Click (Sender: TOBJECT);

Private

{Private Declarations}

public

{Public declarations}

END;

// Define the thread class

Type

TLISTTHREAD = Class (TTHREAD)

Private

Str: string;

protected

Procedure addtolist; // Add STR to listbox components

Procedure execute; override;

public

LBOX: TListBox;

END;

/ / Define variables

VAR

FORM1: TFORM1;

Letters: string = 'aaaaaaaaaaaaaaaaaaaa; // global variable

IMPLEMENTATION

{$ R * .dfm}

// Thread class implementation

Procedure tlistthread.execute;

VAR

I, J, K: Integer;

Begin

For i: = 0 to 50 do

Begin

For j: = 1 to 20 do

For K: = 1 To 1000 do // Cycle 1000 increases in the chance of conflicting

IF letters [j] <'Z' Then

Letters [J]: = SUCC (Letters [J])

Else

Letters [J]: = 'a';

Str: = letters;

Synchronize (addtolist); / / Synchronize access VCL visual components

END;

END;

Procedure tlistthread.addtolist;

Beginlbox.Items.Add (STR); // Add STR to the list box

END;

// Window Class Implementation

Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);

VAR

TH1, TH2: TLISTTHREAD;

Begin

Listbox1.clear;

Listbox2.clear;

TH1: = TLISTHREAD.CREATE (TRUE); // Create thread 1

TH2: = TLISTHREAD.CREATE (TRUE); // Create thread 2

Th1.lbox: = ListBox1;

TH2.LBOX: = ListBox2;

TH1.Resume; // Start execution

TH2.Resume;

END;

End.

As can be seen from the above example, when a plurality of threads modify a public variable, a conflict occurs, so we have to try to prevent it, so that we develop multi-thread applications can run stable. Let's improve it. Let us use the critical paragraph to serialize and achieve synchronization. Was added to the uses section of the embodiment unit1.pas code SyncObjs means added global critical section variable (TRTLCriticalSection) Critical1, was added InitializeCriticalSection (Critical1) FormCreate this code, the event was added DeleteCriticalSection (Critical1) this code in the event FormDestroy , Then modify the TListThread.execute function, the modified code seems as shown below (► To add code):

Procedure tlistthread.execute;

VAR

I, J, K: Integer;

Begin

For i: = 0 to 50 do

Begin

►TercriticalSection (critical1); // enters the critical section

For j: = 1 to 20 do

Fork: = 1 to 3000 DO

IF letters [j] <'Z' Then

Letters [J]: = SUCC (Letters [J])

Else

Letters [J]: = 'a';

Str: = letters;

►LeaveCriticalSection (critical1); // Exit the critical section

Synchronize (addtolist);

END;

END;

Ok, recompile, the results are shown below:

The program successfully avoids conflict, it seems really simple, we have succeeded! Of course, we can also use other synchronization techniques such as Mutex (mutually exclusive objects), Semaphore, etc., these technologies are all direct to us through the API.

Here, summarize several thread synchronization techniques commonly used by Windows.

1. Critical Sections, if there is a portion that cannot be executed simultaneously by two or more threads, the code can be used to perform serialization with a critical section. It can only be used in a separate process or a separate application. The method is as follows: // InitializeCriticalsection (critical1) // in the form destroy DeleteCriticalSection (critical1) // in the thread EntercriticalSection (critical1) ... Protected code LeaveCriticalSection (critical1)

2. MUTEX (mutually exclusive) is a global object used to serialize access resources. We first set the mutually exclusive object, then access the resource, and finally release the mutual exclusive object. When setting a mutex, if another thread (or process) attempts to set the same mutex, the thread will stop until the previous thread (or process) releases the mutex. Note that it can be shared by different applications. The use method is as follows: // HMutex: = Createmutex (NIL, FALSE, NIL) in the form is destroyed in the form, WaitForsingleObject (hmutex, infinite) in the process ... Protection code ReleaseMutex (HMutex) 3. Semaphore, which is similar to the mutex, but it can count. For example, a given resource is allowed to be accessed by three threads simultaneously. In fact, Mutex is a Semaphore for maximum counts. The use method is as follows: // HSEMAPHORE: = CreateSemaphore (NIL, LinitialCount, Lmaximumumcount, LPNAME) // in the form destroy, WaitForsingleObject (HSEMaphore, Infinite) in the process ... Protection Code ReleaseSemaphore (HSemaphore, Lreesecount, LPPREVIOUSCOUNT)

4. You can also use the TCRITicalSECTION in Delphi, which is defined in Syncobjs.PAS.

When you develop multithreaded applications, and multiple threads accesses a shared resource or data, you need to consider the problem of thread synchronization.

If you want to get the electronic version of this article and its source code, please download it on the http://codehunter.1yes.net website.

2001

year

9

month

5

Day Wednesday

转载请注明原文地址:https://www.9cbs.com/read-28136.html

New Post(0)