操作系统(一)协作进程临界区一些代码理解--Peterson’s Solution

来源:互联网 发布:java获取post请求415 编辑:程序博客网 时间:2024/05/23 13:16

Process Synchronization

  • The Critical-Section Problem (临界区问题)
  • Peterson’s Solution
    Concurrent access to shared data may result in data inconsistency.
    Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes.
    Suppose that we wanted to provide a solution to the consumer-producer problem that fills all the buffers. We can do so by having an integer count that keeps track of the number of full buffers. Initially, count is set to 0. It is incremented by the producer after it produces a new buffer and is decremented by the consumer after it consumes a buffer.
while (true) {          /*  produce an item and put in nextProduced  */          while (count == BUFFER_SIZE); // do nothing               buffer [in] = nextProduced;               in = (in + 1) % BUFFER_SIZE;               count++;} 
while (true)  {            while (count == 0); // do nothing                nextConsumed =  buffer[out];                 out = (out + 1) % BUFFER_SIZE;                      count--;            /*  consume the item in nextConsumed    }

在这里要清楚有一个producer和一个consumer,也就是说生产者不断地把生产出来的数据撇进buff里面,消费者不断从buff里面找吃的。那么就要面临这一个空满的问题,当buff为满的情况下,生产者的产品就没办法撇进去了,同理,当buff为空的时候,消费者只能饿肚子了,所以就是饥饿状态。

所以,在第一个程序里,【while (count == BUFFER_SIZE); // do nothing】只有count不满时,才能往下执行,否则,就处于盲等待。而且buff的设计是一个循环队列【队尾进入,对头出去】,所有就有取模的那一行语句。当数据成功撇进buff后,count加一。

消费者进程同理,先判断是否为空,如果不为空,把数据取走,然后count减一。

但是问题来了,你有没有想过count加一减一,谁先谁后的问题呢?!

  • Race Condition (竟争条件)

    • Race condition: The situation where several processes access and manipulate shared data concurrently. The final value of the shared data depends on the particular order in which the access takes place.

    • To prevent race conditions, concurrent processes must be synchronized.(同步)

count++ could be implemented as     register1 = count     register1 = register1 + 1     count = register1
count-- could be implemented as     register2 = count     register2 = register2 - 1     count = register2
Consider this execution interleaving (交错) with “count = 5” initially:    S0: producer execute register1 = count   {register1 = 5}    S1: producer execute register1 = register1 + 1   {register1 = 6}     S2: consumer execute register2 = count   {register2 = 5}     S3: consumer execute register2 = register2 - 1   {register2 = 4}     S4: producer execute count = register1   {count = 6 }     S5: consumer execute count = register2   {count = 4}

所以由代码三可以看出,count的结果有4,5,6三种情况。所以必须要考虑执行代码的先后了。由此引进互斥思想。但是有了互斥也不是万事大吉,还必须满足有限等待条件,有空让进,也就说一个程序不能无限地阻塞,下一个程序遥遥无期,造成资源的浪费。

Mutual Exclusion - If process Pi is executing in its critical section, then no other processes can be executing in their critical sections.
互斥条件。假定进程Pi在其临界区内执行,其他任何进程将被排斥在自己的临界区之外.

Progress - If no process is executing in its critical section and there exist some processes that wish to enter their critical section, then the selection of the processes that will enter the critical section next cannot be postponed indefinitely.
有空让进。临界区没有进程执行,但有些进程需要进入临界区,不能无限期地延长下一个要进入临界区进程的等待时间.

Bounded Waiting - A bound must exist on the number of times that other processes are allowed to enter their critical sections after a process has made a request to enter its critical section and before that request is granted.
有限等待。在一个进程提出进入临界区的请求和该请求得到答复的时间内,其他进程进入临界区的次数必须是有限的。

General structure of process Pido {            entry section       /*(进入区)*/                critical section/*(临界区)*/            exit section        /*(退出区)*/                reminder section/*(剩余区)*/        } while (1);
  • Peterson’s Solution
  • Two process solution.
  • Assume that the LOAD and STORE instructions are atomic; that is, cannot be interrupted.
  • The two processes (P0, P1) share two variables:
    • int turn;
    • Boolean flag[2]
  • The variable turn indicates whose turn it is to enter the critical section.
  • The flag array is used to indicate if a process is ready to enter the critical section. flag[i] = true implies that process Pi is ready!
while (true) {               flag[i] = TRUE;               turn = j;               while ( flag[j] && turn ==  j);                       CRITICAL SECTION               flag[i] = FALSE;                       REMAINDER SECTION       }

以上程序可以这么理解,因为进程的协同性,你可以想象还有很多个和它长的一样的程序在不断并发执行中。flag可以理解为一个全局的锁,仅有一个人能打开,turn是每个局部程序的个人需求,当且仅当局部程序有进入的需求(turn=j)和手中掌握着打开那把锁的钥匙(flag[j]!=true)才能成功地进入临界区。flag[i]=flase为释放资源。再增加一下一段代码,方便理解。

while (true) {               flag[j] = TRUE;               turn = i;               while ( flag[i] && turn ==  i);                       CRITICAL SECTION               flag[j] = FALSE;                       REMAINDER SECTION       }

flag是一个全局变量,由这个程序和上一个程序比较,就能更加直观了,当这程序打开了锁,那么flag[j]=true是毫无疑问的了,与此同时,上一个程序就会在这一行程序忙等待while ( flag[j] && turn == j)。这样就好理解了吧!?