问题描述

  1. 本问题只针对单个生产者进程和单个消费者进程的问题进行讨论。
  2. 生产者进程和消费者进程之间通过共享内存的方式进行IPC通信。
  3. 环形缓冲区存放在共享内存中,并且环形缓冲区中环形缓冲单元的个数为 2^N 个(N为大于1的正整数),环形缓冲区的数据结构定义为:
     #define RING_BUFFER_SIZE N
        
     struct RingBuffer{
         int w_pos; //环形缓冲区写入位置值
         int r_pos; //环形缓冲区读取位置值
         data_block data[(1<<N)]; //data_block 是环形缓冲区中所存放的数据单元的类型
     }
    

    在创建环形缓冲区之后,RingBuffer 结构体中的成员w_posr_pos都被初始化为 0。

  4. 判断环形缓冲区是否为空的伪代码:
     if((w_pos - r_pos) == 0)
         //判断语句为真,RingBuffer 为空
    
  5. 判断环形缓冲区是否为满的伪代码:
     if((w_pos - r_pos)%(1<<(N+1)) == (1<<N))
         //判断语句为真,RingBuffer 为满
    
  6. 生产者进程中的处理逻辑伪代码:
     while(1)
     {
         if((w_pos - r_pos)%(1<<(N+1)) == (1<<N)) //缓冲区满了
         {
             sleep(1);
             continue;
         }
        
         //否则,则将数据填入到环形缓冲区中空闲的单元中
         data[w_pos%(1<<N)] = some_data; //将需要写入的数据写入到指定的环形缓冲区单元中
            
         w_pos++; //将写入位置向前移动
     }
    
  7. 消费者进程中的处理逻辑伪代码:
     while(1)
     {
         if((w_pos - r_pos) == 0)) //缓冲区为空
         {
             sleep(1);
             continue;
         }
        
         //否则,从环形缓冲区中读取数据出来进行处理
         process(data[r_pos%(1<<N)]); //process() 函数只是对读取到的数据进行一个处理
            
         r_pos++; //将读取位置向前移动
     }
    

    疑惑?

    如果按照上面提出的条件和处理逻辑,当生产者进程和消费者进程同时运行时,如果不加互斥锁,上面代码是否会出现Bug,或者不确定的状态?

而且我想了很多遍生产者和消费者的处理逻辑,他们只会在最后执行语句 w_pos++r_pos++ 时改变两个进程都共享的值,虽然 w_pos++r_pos++ 的操作不是原子操作的,但是好像是不是原子操作都不会对结果产生影响,我就是在这里思考不清楚!不知道大家对此有什么看法呢?能否举出特殊的栗子来描述一下。