Implement spin locks by yourself

Source: Internet
Author: User

Note: Part of this article comes from <operating system concepts> Version 6, [US] abraham silberschatz, Peter Baer Galvin, Greg Gagne, translated by Zheng jiegen. In case of any mistakes, I hope you can correct them. I would like to thank you first.

A lock is a mechanism proposed to solve the mutual exclusion between some resources (also known as critical resources. Common locks include read/write locks, mutex locks, and spin locks. Next we will talk about this spin lock. The spin locks and mutex locks are used in almost the same way. At each moment, only one execution unit occupies the lock, and the unit that occupies the lock can obtain the right to use critical resources, this achieves the purpose of mutual exclusion.

The difference between a spin lock and a mutex lock is that, before the execution unit acquires the lock, if other execution units are occupying the lock, the spin lock will continuously judge the lock status, it does not block itself until the lock is released. Because of the constant "Spin" while waiting, this is why it is called a spin lock. So spin locks consume a lot of CPU resources. When the execution unit waits for the lock to be released, the mutex lock blocks itself and puts it in the queue. When the lock is released, it will wake up the execution unit on the queue to put it into the ready queue, and the schedulingAlgorithmFor scheduling and execution. Therefore, the context switch of the process will occur when the mutex lock is used. This may be a non-time-consuming operation, but it will not waste CPU resources while waiting for the lock. Therefore, the use of the two locks must be handled as appropriate.

Now we can implement the spin lock by ourselves, that is, the software-level spin lock.

First, we will introduce several concepts:

Access zone:Implement lock requestCodeSegment (red code)
Critical section:Code segment for mutex execution
Exit:Code segment for unlocking (purple code)
Remaining zone:Other code segments

There are N processes {P0, P1, P2,..., PN }.

Now let's talk about how to do this when the number of execution units (that is, processes) is 2. The following processes are used to represent independent execution units. First, we can use a shared variable turn to indicate which process is currently being executed. The code structure of process I is as follows, where J = 1-I.

 
Do{While (turn! = I); // enter the zone//Critical section ......Turn = J; // exit zone//Remaining zone ......}While(1);

When you carefully observe this code, you will find the following problems: the initial value of the turn determines the execution sequence of the process. If the initial value of "Turn" is 0, process 1 will not be able to be executed before process 0 is executed. Therefore, if process 0 does not want to be executed at all, it is necessary to wait even if process 1 is in a hurry. This problem also exists when turn = 1. In addition, process 0 and process 1 are strictly executed in turn. If no one in the middle is executed, the other will not. We also say that this implementation does not meet the limited wait. That is, a process will never be able to execute.

Next, consider another Implementation Scheme: Set the shared variable Boolean flag [2] and the initial value is false. The code structure of process I is as follows, where J = 1-I.

Do{Flag [I]= True; // enter the zone while (flag [J]);//Critical section ...... Flag [I] = false;//Remaining zone ......}While(1);

This Code meets the requirement of limited waiting, that is, if process 0 is not executed, process 1 can also be executed. However, because two processes are concurrently executed, the following execution process may occur:
P0: Flag [0] = true;
P1: Flag [1] = true;
P0: While (flag [1]);
P1: While (flag [0]);

In this case, the deadlock occurs, that is, P0 waits for the flag [1] to become false, and P1 waits for the flag [0] to become false. We say this code does not meet the requirements of the frontend. The above two sections of Code ensure that only one process can execute the code in the critical section at a time, so they all meet mutual exclusion.

To verify that an algorithm is implemented correctly, you must verify that the Code meets the following three attributes:

1: Mutual Exclusion // only one process enters the critical section at a time
2: No Deadlock
3: limited wait // a process does not wait infinitely and cannot be executed.

The first correct Software Solution to the Problem of mutual exclusion between two processes was proposed by the Dutch mathematician T. Dekker, also known as the Dekker algorithm. The Code of process I in the Dekker algorithm is as follows, where J = 1-I. The two processes share Boolean flag [2] and turn. Flag Initialization is false, and turn is 0 or 1.

  1   DO  {  2 flag [I] = ture; // start to compete 3 while (flag [J]) {// PJ is competing 4 If (turn = J) {// It should be PJ's turn to execute 5 Flag [I] = false; // take the initiative to give up 6 While (turn = J ); // PI waits for PJ to release the lock 7 flag [I] = true; // re-start competition 8} 9}   10   //   critical section ......   11 turn = J; // automatically backend 12 flag [I] = false; // discard competition   13  ///   remaining area ......   14 }< span style = "color: # 0000ff; "> while  ( 1 ); 

Mutual Exclusion:If P0 and P1 are both in the critical section, both flag [0] and flag [1] are false. Flag [0] is false only when turn = 1, and flag [1] is false only when turn = 0. P0 and P1 do not change the value of the turn before the critical section, so there is only one value before the turn. This indicates that the turn is 0 and 1, which is obviously impossible. Therefore, only one P0 and P1 executes the critical code.

Frontend:When the flag is initialized, the process that does not participate in the competition will not affect the process that participates in the competition. Because the turn operation can only have one value at a time, there will always be a process that voluntarily gives up competition and will not generate deadlocks, so that another process can be executed.

Limited wait:If P0 is in the critical section while P1 is waiting (6th lines of code), P0 will execute at most once after the execution of P1 7th lines of code is completed, so that P0 will have a chance to execute. Even more interestingly, although the algorithm meets the limited waiting conditions, it cannot accurately calculate the number of times that another process can be executed. The reason is that P1 may be executed many times before the execution of the 7th-line code.

We can see that this algorithm is correct, but it is difficult to prove it. In fact, Peter son proposed the simplest solution for the two processes in 1981. The algorithm code is as follows, where J = 1-I.

Do{Flag [I]= True; // start competition turn = J; // actively push the while (flag [J] & turn = J); // wait//Critical section ......Flag [I] = false; // discard the competition//Remaining zone ......}While(1);

Mutual Exclusion:If P0 and P1 are both in the critical section, the turn is equal to 0 and equal to 1, which is obviously impossible. Therefore, only one process enters the critical section.

Frontend:Because each turn has only one value, a while loop of a process is not valid and will not be deadlocked.

Limited wait:Suppose P1 enters the critical section, P0 is waiting and turn = 1. After P1 is executed, it is automatically pushed before the next competition, so that P0 has the opportunity to execute it. P0 can be executed once at most after P1 is executed.

Now we will discuss the solutions for multiple processes. The solutions for multiple processes are much more complex than those for process 2. Dijkstra provided the first solution to the problem of mutual exclusion between N processes in 1965. However, in this method, there was no upper limit on the number of times a process had to wait before it was allowed to enter the critical section. Then knuth gave the first restricted algorithm in 1966, which is limited to the Npower of 2. Then debrujin improved the knuth algorithm and reduced the number of waits to N ^ 2. Later, Eisenberg and McGuire successfully reduced the number of times to n-1. Lamport developed the most famous bakery algorithm, and its waiting time is n-1.

Let's talk about this bakery algorithm. The basic idea of the bakery algorithm is: the process that needs to enter the critical section first needs to draw a number, and the process that gets the minimum number enters the critical section. If two processes get the same number, the process with the smallest number enters the critical section.

Compare a number pair (number [I], I). If (number [I], I) <(number [J], J ), then PI enters the critical section.

(Number [I], I) <(number [J], J) equivalent to (number [I] <number [J] | Number [I] = number [J] & I <j)

N processes share Boolean choosing [N], int number [N], initialize choosing to false, and number to 0. The process pi code is as follows:

  1: DO  {< span style =" color: # ff0000; "> 2: Choosing [I]   = true; // start number 3: Number [I] = max (number [0], number [1], ......, number [N-1]); // number 4: Choosing [I] = false; // number 5: For (j = 0; j 
   
     9: 
    ///   critical section ......   10:   Number [I] = 0; // The number obtained is cleared. The next time you draw the number again,  11:   //   remaining zone ......   12: }< span style = "color: # 0000ff; "> while  ( 1 ); 

We can see that each process must draw a number before entering the critical section. After the number is drawn, it cannot enter the critical section immediately. Instead, it must be compared with all processes that have completed the number, if there are smaller than themselves, they will wait through the while loop.

Mutual Exclusion:Assume that PI and PK enter the critical section at the same time. In this case, neither number [I] nor number [k] is equal to 0. In this case, (number [I], I) and (number [K], k) must be able to compare the size, and it must be a small one. If (number [I], I) is small, the PK is in a loop; otherwise, the PI is in a loop, which conflicts with the two processes in the critical section at the same time. Therefore, mutual exclusion is established.

Frontend:Because (number [I], I )! = (Number [J], j) When I! = J, that is to say, at any time, only one process is the smallest, so that at least one process can be executed, so there will be no deadlock.

Limited wait:First, it can be determined that the process of not participating in the competition will not affect the process of participating in the competition. In addition, we assume that the execution sequence of the process is determined by drawing lots in the first round.

P0, P1, P2 ,...... P (n-1), when P0 is executed, the number drawn by the next number is greater than the number drawn by the process that has completed the number, therefore, it will be executed only after the waiting process is completed.
As shown in the following figure, P0, P1, P2, ...... represents the initial execution order. After each process is executed, the number is re-drawn, and the position sorting is placed on the right.

P0, P1, P2,..., P (n-1) |P0 is executing P1, P2,..., P (n-1) |P0 P0 execution completed and re-drawn, P1 is executing P2,..., P (n-1) |P0, P1 P1 completed and re-drawn, P2 is executing P3,..., P (n-1) |P0, P1, P2 P2: Execution completed and re-drawn. P3: Execution in progress.|..|. Select Phase 1 select phase 2

The number drawn in the second selection phase is generally greater than that drawn in the first selection phase. Therefore, each process in the first selection phase will have the opportunity to execute. In addition, a maximum of N-1 processes can be executed after execution is completed. Therefore, the limited wait is true.

Next, let's take a closer look at the meaning of each line of code for this algorithm: choosing is initialized to false, and number is initialized to 0.
Line 6 and 7 of the Code ensure that the process that does not compete for the critical section does not affect the competition of other processes.
The 3rd line of code ensures that the number of the process that draws the number is small, the number of the process that draws the number is large, and the number of the process that draws the number is as big as the number.
The 6th line of code ensures that every decision is made when the numbers of all competing processes are drawn, ensuring fairness.
The 7th line of code ensures that the process PI running in the critical section must be (number [I], I) the smallest.

Through object-oriented encapsulation, it is easy to implement a spin lock object. Lock () is the code for entering the Zone, and unlock () is the code for exiting the zone. You can design your own details, this is not much to be said here.

related literature:
Dijkstra [1965]: E. w. dijstra, "cooperating sequential processes", Technical Report, clinical University. eindhoven, The Netherlands, 1965, pages 43 ~ 112.
Peterson [1, 1981]: G. l. peterson, "myths about the mutual exclusion problem", information processing letters, Volume 12, number 3,1981.
knuth [1, 1966]: D. e. knuth, "additional comments on a problem in concurrent programming control", communications of the ACM, Volume 9, number 5, 1966, pages 321 ~ 322.
debruijn [1, 1967]: N. g. debruijn, "additional comments on a problem in concurrent programming and control", communicaitonsof the ACM, Volume 10, Number 3, 1967, pages 137 ~ 138.
Eisenberg and McGuire [1972] M. a. eisenberg and M. r. mcGuire, "future comments on Dijkstra's concurrent programming controlproblem", communications of the ACM, Volume 15, number 11,197 2, pages 999.
Lamport [1, 1974]: l. lamport, "a new solution of dijstra's concurrent programming problem", communication of the ACM, volume
17, number 8, 1974, pages 453 ~ 455.

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.