Multi-thread shared resource conflict

Source: Internet
Author: User

Methods for multi-thread synchronization in Delphi
When there are multiple threads, you often need to synchronize these threads to access the same data or resource. For example, assume there is a program where one thread is used to read the file into the memory, and the other thread is used to count the characters in the file. Of course, it makes no sense to count the entire file before it is transferred to the memory. However, since each operation has its own thread, the operating system will regard the two threads as separate tasks for separate execution, so that the number of words may not be counted when the entire file is loaded into the memory. To solve this problem, you must synchronize the two threads.
There are some thread synchronization address problems. Win32 provides many thread synchronization methods. In this section, you will see how to use the critical section, mutex, semaphore, and event to solve the thread synchronization problem.

1. Critical Section
The critical section is the most direct thread synchronization method. A critical section is a piece of code that can only be executed by one thread at a time. If the code of the initialization array is placed in the critical section, the other thread will not be executed until the first thread finishes processing.
Before using the critical section, you must use the initializecriticalsection () process to initialize it.
The statement is as follows:
Procedure initializecriticalsection (VAR
The lpcriticalsection parameter is a record of the trtlcriticalsection type and is a variable parameter. It does not matter how the trtlcriticalsection is defined, because it is seldom necessary to view the specific content in this record. You only need to pass uninitialized records in the lpcriticalsection. The initializecriticalsection () process will fill in this record.
Note that Microsoft intentionally concealed the details of trtlcriticalsection. Because its content is different on different hardware platforms. On intel-based platforms, the trtlcriticalsection contains a counter, a domain indicating the current thread handle, and a system event handle. On the Alpha platform, the counter is replaced with an alpha-CPU data structure, called a spinlock. After the record is filled, we can create a critical section. In this case, we need to use entercriticalsection () and leavecriticalsection () to encapsulate the code block. The two processes are declared as follows:

Procedure entercriticalsection (VAR lpcriticalsection: trrlcriticalsection); stdcall;
Procedure leavecriticalsection (VAR
As you may think, the parameter lpcriticalsection is the record filled by initializecriticalsection.
When you do not need a trtlcriticalsection record, you should call the deletecriticalsection () process. The following is its declaration:
Procedure deletecriticalsection (VAR

2. Mutual Exclusion
Mutex is very similar to a critical section. Apart from two key differences: first, mutex can be used for cross-process thread synchronization. Second, mutex can be assigned a string name, and an additional handle of an existing mutex object is created by referencing this name.
The biggest difference between a critical section and an event object (such as a mutex object) is performance. When there is no thread conflict in the critical section, use 1 0 ~ 1 5 time slice, and the event object needs to use 400 ~ 600 time slices.
You can call createmutex () to create a mutex. The Declaration of the function is as follows:
Function

The lpmutexattributes parameter is a pointer to a tsecurityattributtes record. This parameter is usually set to 0, indicating the default security attribute. The binitalowner parameter indicates whether the thread that creates the mutex object must be the owner of the mutex object. If this parameter is set to false, the mutex object has no owner.
The lpname parameter specifies the name of the mutex. If the parameter is not set to nil, the function searches for whether a mutex object with the same name exists. If yes, the function returns the handle of the mutex object with the same name. Otherwise, a new mutex object is created and its handle is returned.
When a mutex object is used, closehandle () should be called to close it.

Use waitforsingleobject () in the program to prevent other threads from entering the code in the synchronization area. The function declaration is as follows:
Function

This function allows the current thread to sleep at the time specified by dwmilliseconds until the object specified by the hhandle parameter enters the signal sending State. When a mutex object is no longer owned by a thread, it enters the signal sending State. When a process is terminated, it enters the sending status. The dwmilliseconds parameter can be set to 0, which means to check whether the object specified by the hhandle parameter is in the sending status and then return immediately. The dwmilliseconds parameter is set to infinite, indicating that if the signal does not appear, it will keep waiting.
The return value of this function is as follows:
Return Value used by the waitfor singleobject () function
Meaning of Return Value
The wait_abandoned specified object is a mutex object, and the thread that owns this mutex object is terminated before the object is released. In this case, the mutex object is discarded. In this case, the mutex object belongs to the current thread and is set to a non-sending State.
Wait_object_0: the specified object is in the sending status.
The wait_timeout wait time has passed, and the object is still declared as a non-sending State. When a mutex object is no longer owned by a thread, it is in the sending State. In this case, the thread that calls the waitforsingleobject () function becomes the owner of the mutex object, and the mutex object is set to not sending a signal. When the thread calls the releasemutex () function and passes a mutex object handle as a parameter, this ownership relationship is removed and the mutex object enters the signal sending State again.
Note that in addition to the waitforsingleobject () function, you can also use the waitformultipleobject () and msgwaitformultipleobject () functions. They can wait for several objects to change to the sending status. For details about the two functions, see the Win32 API online documentation.

3. semaphores
Another technique used to synchronize threads is to use semaphores. It is created on the basis of mutex, but the semaphore adds the resource count function, the number of threads allowed to enter the code to be synchronized at the same time. You can use createsemaphore () to create a semaphore object. Its declaration is as follows:
Function

Like the createmutex () function, the first parameter of createsemaphore () is a pointer to the tsecurityattribute s record. The default value of this parameter can be set to nil.
The linitialcount parameter is used to specify the initial count value of a semaphore, which must be between 0 and lmaximumcount. If this parameter is greater than 0, the semaphore is in the sending status. When the waitforsingleobject () function (or another function) is called, the Count value is reduced by 1. When releasesemaphore () is called, this Count value is added to 1.
The lmaximumcount parameter specifies the maximum value of the Count value. If this semaphore represents a certain resource, then this value represents the total number of available resources.
The lpname parameter is used to give the name of the semaphore object. It is similar to the lpname parameter of the createmutex () function.

------------------------------------------

★★★About thread synchronization:
Synchronize () is run in a hidden window. If your task is busy here, your main window will be blocked; synchronize () only put the code of this thread into the main thread for running, not thread synchronization.

The critical section is the best way to synchronize all threads in a process. It is not a system level, but a process level, that is to say, he may use some signs in the process to ensure thread synchronization in the process. According to Richter, It is a count loop; the critical section can only be used in the same process; the critical section can only wait for an indefinite period, however, 2 K has added the tryentercriticalsection function to implement Zero Wait time.

Mutex ensures thread synchronization between multiple processes. It uses the system kernel object to ensure synchronization. Because the system kernel object can be named, multiple processes can use this kernel object to ensure the thread security of system resources. The mutex is a Win32 kernel object, which is managed by the operating system. The waitforsingleobject can be used for unlimited waiting, zero waiting and any waiting time.

1. Critical Section
The critical section is the most direct thread synchronization method. A critical section is a piece of code that can only be executed by one thread at a time. If the code of the initialization array is placed in the critical section, the other thread will not be executed until the first thread finishes processing. Before using the critical section, you must use the initializecriticalsection () process to initialize it.
After the first thread calls entercriticalsection (), all other threads cannot enter the code block. The next thread will not be awakened until the first thread calls leavecriticalsection.

2. Mutual Exclusion
Mutex is very similar to a critical section. Apart from two key differences: first, mutex can be used for cross-process thread synchronization. Second, mutex can be assigned a string name, and an additional handle of an existing mutex object is created by referencing this name.
Tip: The biggest difference between a critical section and an event object (such as a mutex object) is performance. When there is no thread conflict in the critical section, use 10 ~ 15 time slices, and the event object must use 400 ~ 600 time slices.
When a mutex object is no longer owned by a thread, it is in the sending State. In this case, the thread that calls the waitforsingleobject () function becomes the owner of the mutex object, and the mutex object is set to not sending a signal. When the thread calls the releasemutex () function and passes a mutex object handle as a parameter, this ownership relationship is removed and the mutex object enters the signal sending State again.
You can call createmutex () to create a mutex. When a mutex object is used, closehandle () should be called to close it.

3. semaphores
Another technique used to synchronize threads is to use semaphores. It is created on the basis of mutex, but the semaphore adds the resource count function, the number of threads allowed to enter the code to be synchronized at the same time. You can use createsemaphore () to create a semaphore object,
Because only one thread is allowed to enter the code to be synchronized, the maximum count (lmaximumcount) of the semaphore must be set to 1. The releasesemaphore () function adds 1 To the count of the semaphore object;
Remember, you must call the closehandle () function to release the handle of the semaphore object created by createsemaphore.

★★★Return Value of the waitforsingleobject function:
The wait_abandoned specified object is a mutex object, and the thread that owns this mutex object is terminated before the object is released. In this case, the mutex object is discarded. In this case, the mutex object belongs to the current thread and is set to a non-sending State;
Wait_object_0: the specified object is in the sending status;
The wait_timeout wait time has passed, and the object is still in the non-sending status;

----------------------------------------------
VCL supports three technologies to achieve this goal:
(2) Use the critical area
If the object does not improve the built-in locking function, you need to use the critical area. The critical area may only enter one thread at the same time. To use the critical area, a global tcriticalsection instance is generated. The tcriticalsection has two methods: acquire (to prevent other threads from executing the region) and release (to cancel blocking)

Each critical zone is associated with the global memory you want to protect. Each thread accessing the global memory must first use acquire to ensure that no other thread uses it. After completion, the thread calls the release method so that other threads can use this global memory by calling acquire.

Warning: The critical zone only uses it in all threads to access the global memory. If a thread calls the memory directly without passing acquire, it will cause simultaneous access. For example, lockxy is a global critical partition variable. Any thread that accesses global X and Y variables must use acquire before access.
Lockxy. acquire; {lock out other threads}
Try
Y: = sin (X );
Finally
Lockxy. release;
End
The critical section is mainly used to implement synchronization between threads. However, when using this section, you must create this object outside the thread where the critical object is synchronized (usually a critical object is created in the main thread ).

------------------------------------------------
The thread uses the critical section for synchronization, and the process uses mutex for synchronization.

Delphi encapsulates critical objects. The object name is tcriticalsection. You only need to create this critical object in the main thread (note that this object must be created outside the thread to be synchronized ). Use lock and unlock for specific synchronization.
When a mutex object is created simultaneously between processes, you only need to create a mutex object createmutex. you only need to releasemutex (mutexhandle); When waitforsingleobject (mutexhandle, infinite) Unlock is required for synchronization.

There are many methods, such as signal lights, critical sections, and mutex objects. In addition, global atoms and shared memory can be used in windows. in Windows, when reading and writing an 8-digit integer, you can use this to achieve mutual exclusion. methods that can generate a global name can be synchronized between processes (such as mutex objects), or used for synchronization between threads. Methods that cannot generate a global name (such as a critical section) it can only be used for synchronization between threads.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.