Introduction
Process synchronization is an operating system level concept, in the context of multi-channel programs, there are different constraints, in order to coordinate this mutual restrictive relationship, the realization of resource sharing and process collaboration, so as to avoid conflicts between processes, the introduction of process synchronization.
Critical Resources
In the operating system, a process is the smallest unit of possession (a thread can access all resources within its process, but the thread itself does not own the resource or only has the necessary resources). For some resources, however, they can only be consumed by one process at a time. These resources, which can only be occupied by one process at a time, are called critical resources . A typical critical resource, such as a physical printer, or a number of variables and data shared by multiple processes on a hard disk or in memory (if such resources are not protected as critical resources, is likely to cause data loss).
Access to critical resources must be a mutual complaint. That is, when a critical resource is occupied, another process that requests a critical resource is blocked until the critical resource to which it is requested is released. The code that accesses the critical resource in-process becomes a critical section .
The access process for a critical section is divided into four parts:
1. Enter the zone: see if the critical section is accessible and if so, go to step two or the process will be blocked
2. Critical section: Operation in critical section
3. Exit Area: Clear the critical area is occupied by the flag
4. Remaining area: code for the unrelated part of the process and critical section
the concept of inter-process synchronization and cross-litigation
Process synchronization
Process synchronization is also a direct constraint between processes, two or more threads that are created to accomplish a certain task, and this thread needs to coordinate their work order in some locations to wait for and pass on the information generated by the constraints. The direct relationship between processes stems from the cooperation between them.
For example, process a needs to read the information generated by process B from the buffer, and when the buffer is empty, process B is blocked because it cannot read the information. When process a generates information into the buffer, process B is awakened. As shown in concept 1.
Figure 1: Synchronization between processes
Simulating synchronization between processes with C # code is shown in code 1.
Class Processsyn { private static mutex Mut = new Mutex (); static void Main () { Console.WriteLine ("Process 1 finishes executing process 2 to execute ..."); Thread Thread1 = new Thread (new ThreadStart (Proc1)); Thread Thread2 = new Thread (new ThreadStart (PROC2)); Thread1.start (); Thread2.start (); Console.readkey (); } private static void Proc1 () { mut. WaitOne (); Console.WriteLine ("Thread 1 performs actions ...."); Thread.Sleep (+); Mut. ReleaseMutex ();//v Operation } private static void Proc2 () { mut. WaitOne ();//p Operation Console.WriteLine ("Thread 2 perform operation ...."); Mut. WaitOne (); } }
Code 1. Synchronization between C # simulation processes
Run result 2 as shown.
Figure 2: Running results
Process Mutex
Process mutex is an indirect constraint relationship between processes. When a process enters a critical section using a critical resource, another process must wait. This process is unblocked only if the process that uses the critical resource exits the critical section.
For example, process B needs to access the printer, but when process a occupies the printer, process B is blocked until process a frees up the printer resource and process B can continue. As shown in concept 3.
Figure 3: Mutual exclusion between processes
In C # to simulate the mutual exclusion between processes, here I started 5 threads, but only one thread at a time can access critical resources. As shown in code 2.
Class Processmutex {private static mutex Mut = new Mutex (); Private Const int numthreads = 5; static void Main () {for (int i = 0; I <= numthreads; i++) {Th Read MyThread = new Thread (new ThreadStart (Useresource)); Mythread.name = String.Format ("Thread {0}", i + 1); Mythread.start (); } console.readkey (); }//Synchronize private static void Useresource () {//= equivalent to P operation Mut. WaitOne (); /* The following code is the thread's real work */Console.WriteLine ("{0} has entered the critical section", Thread.CurrentThread.Name); Random r = new Random (); int rnum = R.next (2000); Console.WriteLine ("{0} performs operation, execution time is {1}ms", thread.currentthread.name,rnum); Thread.Sleep (Rnum); Console.WriteLine ("{0} has left the critical section \ r \ n", THREAD.CURRENTTHREAD.NAME); /* Thread Work Ends *///= v operation Mut. ReleaseMutex (); }//Mutex}
Code 2. Mutual exclusion between C # simulation processes
Run result 4 as shown.
Figure 4. C # Simulation Process Mutex
the basic method of realizing the mutual exclusion of critical regions
Hardware Implementation Methods
The simplest way to implement a critical section through hardware is to turn off CPU interrupts. From the computer principle we know that the CPU for process switching is required through interrupts. If you block the interrupt then you can ensure that the current process is running smoothly to complete the critical section code, thereby achieving mutual exclusion. The step of this approach is to interrupt the shield-the execution of the critical section-on the interruption. This is not good, however, which greatly limits the ability of the processor to perform the task alternately. And the right to turn off the interruption of the user code, then if the user code is blocked after the interruption is no longer open, the system is not kneeling?
There is also the implementation of the instructions of the hardware, this way and the next to say the signal volume in the same way. But through the hardware to achieve, here is not elaborate.
Signal Volume Realization Method
This is also what we are more familiar with P v operation. By setting a semaphore s that represents the number of resources, the mutex of the process is achieved by the P and V operations on the Semaphore S.
P and V operate from Dutch Passeren and Vrijgeven, respectively, for possession and release. The P-V operation is the primitive of the operating system, meaning it is atomic.
The P operation first reduces the semaphore, indicating that a process will occupy or wait for the resource, and then detect if S is less than 0, if less than 0 is blocked, and if greater than 0 Occupy resources for execution.
The V operation is the opposite of the P operation, which increases the semaphore first, indicating that the process that occupies or waits for resources has been reduced by 1. It then detects if s is less than 0, and if less than 0 wakes up other processes waiting to use the S resource.
In front of our C # simulation process synchronization and mutual exclusion is actually a semaphore to achieve.
some classical use of signal volume to achieve synchronization problems
Producer-Consumer issues
Problem Description: Producer-consumer problem is a classic process synchronization problem, which was first proposed by Dijkstra to demonstrate the semaphore mechanism he proposed. This job requires the design of two threads to be executed within the same process address space. The producer thread produces the item and then places the item in an empty buffer for consumption by the consumer thread. The consumer thread obtains the item from the buffer and then releases the buffer. When a producer thread produces an item, if no empty buffers are available, the producer thread must wait for the consumer thread to release an empty buffer. When consumer threads consume items, if there is no full buffer, then the consumer thread will be blocked until the new item is produced
Here producers and consumers are both synchronous and mutually exclusive relationship, first, only producer production, consumption can be consumed, here is a synchronous relationship. But their access to the critical section is mutually exclusive. Therefore, three semaphores are required for the synchronous buffer, empty and full, and the Mut variable is mutually exclusive when accessing the buffer.
Use C # to simulate the relationship between producers and consumers as shown in code 3.
Class Producerandcustomer {//critical area semaphore private static Mutex Mut = new Mutex (); private static Semaphore empty = new Semaphore (5, 5);//idle buffer private static Semaphore full = new Semaphore (0, 5); Producer-consumer analog static void Main () {Console.WriteLine ("Producer consumer Simulation ..."); for (int i = 1; i < 9; i++) {Thread Thread1 = new Thread (new ThreadStart (Producer)); Thread Thread2 = new Thread (new ThreadStart (Customer)); Thread1.name = String.Format ("producer thread {0}", i); Thread2.name = String.Format ("Consumer thread {0}", i); Thread1.start (); Thread2.start (); } console.readkey (); } private static void Producer () {Console.WriteLine ("{0} already started", THREAD.CURRENTTHREAD.N AME); Empty. WaitOne ();//P operation mut for empty. WaitOne ();//P Operation Console for Mut. WriteLine ("{0} put data into critical section", Thread.CurrentThread.Name); Thread.Sleep (1000); Mut. ReleaseMutex ();//V Operation full for mut. Release ();//V operation for full} private static void Customer () {Console.WriteLine ("{0} already started", Thread.CurrentThread.Name); Thread.Sleep (12000); Full. WaitOne ();//P operation Mut for full. WaitOne ();//P Operation for Mut Console.WriteLine ("{0} Read critical section", Thread.CurrentThread.Name); Mut. ReleaseMutex ();//V operation on mut empty. Release ();//V Operation for Empty}}
Code 3: Using C # to simulate the relationship between producers and consumers
Run result 5 as shown.
Figure 5: Producer Consumer C # simulation results
Reader--Writer's question
Problem Description:
A data file or record, collectively known as a data object, can be shared by multiple processes, some of which require read only as "readers", while others require writing or modifying called "writer".
Rule: Allow multiple readers to read a shared object at the same time, but prohibit the reader or writer from accessing a shared object at the same time, and also prohibit multiple writer from accessing a shared object, otherwise it will violate the Bernstein concurrency execution condition.
Through the description can be analyzed, the reader and writer here is mutually exclusive, and the writer and writer are mutually exclusive, but the reader is not mutually exclusive.
Thus we can set up 3 variables, one to count the number of readers, the other two for the reader to read and write the mutual exclusion, the reader and the reader and the writer's mutual exclusion. As shown in code 4.
Class Readerandwriter {private static mutex Mut = new Mutex ();//Mutex used to protect the number of readers private static mutex RW = New Mutex ();//Guaranteed reader writer mutex semaphore static int count = 0;//reader number static void Main () { Console.WriteLine ("Reader-writer simulation ..."); for (int i = 1; i < 6; i++) {Thread Thread1 = new Thread (new ThreadStart (Reader)); Thread1.name = String.Format ("Reader thread {0}", i); Thread1.start (); } Thread Thread2 = new Thread (new ThreadStart (writer)); Thread2.name = String.Format ("writer thread"); Thread2.start (); Console.readkey (); } private static void Reader () {Mut. WaitOne (); if (count = = 0) {rw. WaitOne (); } count++; Mut. ReleaseMutex (); Thread.Sleep (New Random (). Next (2000));//Read Time 1S Console.WriteLine ("Read Complete"); Mut. WaitOne (); count--; Mut. ReleaseMutex (); if (count = = 0) {rw. ReleaseMutex (); }} private static void writer () {rw. WaitOne (); Console.WriteLine ("Write Data"); rw. ReleaseMutex (); }
Code 4. C # simulates reader and writer issues
Run result 6 as shown.
Figure 6: The results of the reader's work
The question of the Philosopher's meal
Problem Description:
There are five philosophers whose way of life is to think and dine alternately. The philosophers shared a round table with five chairs around them, each seated. There were five bowls and five chopsticks in the round table, and when a philosopher thought, he did not talk to others, and when he was hungry he tried to take the chopsticks that were closest to his left and right, but he could not get one. Only when he got two chopsticks, the party can eat, after eating, put down chopsticks and continue to think.
Figure 7: The question of the Philosopher's meal
According to the problem description, five philosophers can be regarded as five processes respectively. Five chopsticks are regarded as five resources respectively. It is only when philosophers have the right and left resources to eat. If you do not specify a rule, when each philosopher holds only one chopstick in his hand, it causes a deadlock, so that five philosophers starve to death for not eating food. So our strategy is to let the philosopher pick up two chopsticks at the same time. So we need to set a semaphore for each resource, and we need to make the philosopher pick up two chopsticks at the same time and set a mutex semaphore, as shown in code 5.
Class Philosopher {private static int[] Chopstick=new int[5];//represents the philosopher's 5 chopsticks private static Mutex eat = N EW Mutex ();//used to ensure that philosophers pick up two pairs of chopsticks at the same time static void Main () {//initial setting all chopsticks available for (int k = 1; k <= 5; k++) {chopstick[k-1] = 1; }//Each philosopher turns to dine once for (int i=1;i<=5;i++) {Thread Thread1 = new Thread (new ThreadStart (philosophers)); Thread1.name = i.ToString (); Thread1.start (); } console.readkey (); } private static void Philosophers () {//If the chopsticks are not available, wait 2 seconds while (chopstick[in T.parse (Thread.CurrentThread.Name)-1]!=1 | | chopstick[(int. Parse (Thread.CurrentThread.Name))%4]!=1) {Console.WriteLine ("philosopher {0} is waiting", thread.currentthread. Name); Thread.Sleep (2000); } eat. WaitOne (); Pick up two pairs of chopsticks at the same time Chopstick[int. Parse (Thread.CurrentThread.Name)-1] = 0; chopstick[(int. Parse (Thread.CurrentThread.Name))% 4] = 0; Eat. ReleaseMutex (); Thread.Sleep (1000); Console.WriteLine ("Philosopher {0} is dining ...", Thread.CurrentThread.Name); After the meal, put down the chopsticks chopstick[int. Parse (Thread.CurrentThread.Name)-1] = 1; chopstick[(int. Parse (Thread.CurrentThread.Name))% 4] = 1; Console.WriteLine ("Philosopher {0} to finish the meal, continue to think", Thread.CurrentThread.Name); } }
Code 5. C # Mock Philosophers dining problem
Run result 7 as shown.
Fig. 8. Operational results of the Philosopher's question
Summary
This paper introduces the concept of process synchronization and mutual exclusion, the concept of critical section, and the way to implement synchronization mutual exclusion, and solves 3 kinds of classical problems of synchronization, and gives the corresponding C # simulation code. Operating System management of processes is one of the foundations of computer programming, so mastering this concept will make your internal skills a whole higher level:-D
Operating system principle---the concept of process synchronization and mutual exclusion in the operating system