博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PV操作--demo test
阅读量:4167 次
发布时间:2019-05-26

本文共 2771 字,大约阅读时间需要 9 分钟。

前言

      操作系统的pv操作的认识,每次都有不一样的感受,近期自己再一次接触到PV操作,生产者消费者的问题,从代码的角度体会了一下,有不一样的认识和体会。


认识

      信号量(Saphore)由一个值和一个指针组成,指针指向等待该信号量的进程。信号量的值表示相应资源的使用情况。信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个资源,因此S的值减1;当S<0时,表示已经没有可用资源,S的绝对值表示当前等待该资源的进程数。请求者必须等待其他进程释放该类资源,才能继续运行。而执行一个V操作意味着释放一个资源,因此S的值加1;若S<0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。

这里写图片描述

对于PV操作的一些疑问:

  • S大于0的时候不唤醒资源,小于0的时候为什么要唤醒资源?

    S大于0表示,有临界资源可以使用,也就是这个时候没有进程阻塞在资源上,所以不需要被唤醒。S小于0的时候,我们要说一下V操作的原语,本质在于:一个进程使用完临界资源后,释放临界资源,使S加1,以通知其它的进程,这个时候如果S<0,表明有进程阻塞在该类资源上,因此要从阻塞队列里唤醒一个进程来“转手”该类资源,所以这个的前提是V操作哦。

  • S的绝对值表示等待的进程数,同时又表示临界资源,如何区分一下呢?

    当信号量S小于0时,其绝对值表示系统中因请求该类资源而被阻塞的进程数目.S大于0时表示可用的临界资源数。注意在不同情况下所表达的含义不一样。当等于0时,表示刚好用完。


demo

      一下是动手实现的一个demo,感觉挺有意思的:

//生产者消费者问题//客户端public class ProducerConsumer{
public static void main(String[] args){ SyncStack ss =new SyncStack(); Producer p =new Producer(ss); Customer c =new Customer(ss); new Thread(p).start(); new Thread(c).start(); }}//生产的产品class Product{
int id; //构造函数 Product(int _id){ this.id=_id; } public String toString(){ return "产品:"+id; }}//容器class SyncStack{
int index=0; Product[] Arrpro =new Product[10]; //容器最多可以放10个产品 //容器中放产品的方法 public synchronized void push(Product pro){ //如果满了 if(index ==Arrpro.length){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //唤醒正在等待的线程 Arrpro[index]=pro; index++; } //容器中取产品 public synchronized Product pull(){ if(index ==0){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } this.notify(); //唤醒正在等待的线程 index--; return Arrpro[index]; }}//生产者--申请一个线程class Producer implements Runnable{
SyncStack ss =new SyncStack(); Producer(SyncStack _ss){ this.ss=_ss; } public void run(){ //生产者能够造20个产品 for(int i=0;i<20;i++){ Product pro=new Product(i); ss.push(pro); System.out.println("生产了"+pro); try{ Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); } } }}//消费者class Customer implements Runnable{
SyncStack ss =new SyncStack(); Customer(SyncStack _ss){ this.ss=_ss; } public void run(){ for(int i=0;i< 20;i++){ Product pro =ss.pull(); System.out.println("消费了"+pro); try{ Thread.sleep(2000); }catch (InterruptedException e){ e.printStackTrace(); } } }}

结语

      学习是在不断的认识,不断重复的基础上的,每次学习都get到一个点,会觉得很有意思。

你可能感兴趣的文章
linux内核引导参数解析及添加
查看>>
长短期记忆人工神经网络(LSTM)及其tensorflow代码应用
查看>>
长短期记忆人工神经网络(LSTM)网络学习资料
查看>>
运行网络中搜寻到的python程序代码——以长短期记忆人工神经网络(lstm)python代码为例
查看>>
闪存文件系统(Flash File System)
查看>>
WinMIPS64工具进行MIPS指令集实验(一)
查看>>
WinMIPS64工具进行MIPS指令集实验(二)
查看>>
Linux上快速入门英特尔Optane DC Persistent Memory Module的配置与使用
查看>>
Intel Optane DC Persistent Memory Module (PMM)详解
查看>>
Ubuntu 18.04安装英特尔Optane DC Persistent Memory Module配置工具ipmctl
查看>>
NUMA架构下的CPU拓扑结构
查看>>
如何判断变量在内存中如何放置的?低位在前还是高位在前
查看>>
c语言中通过指针将数值赋值到制定内存地址
查看>>
64位与32位linux c开发时默认字节对齐值
查看>>
malloc(malloc在32位编译系统中分配的地址会8字节对齐,64为编译系统中会8或者16字节对齐)
查看>>
初始化时共享内存的key值和信号量初始化的key值可以一样
查看>>
linux创建线程之pthread_create
查看>>
pthread_attr_init线程通俗举例讲解与线程属性
查看>>
进程和线程的区别
查看>>
int main(int argc,char* argv[])详解,以及与int main()有什么区别
查看>>