IPC经典问题

IPC

信号量

semget

  • #include<sys/sem.h>
    int semget(key_t _key ,int _nsems,int _semflg);
    
  • 功能:创建一个新的信号量或获取一个已经存在的信号量的键值。

  • 返回值:成功返回信号量的标识码ID。失败返回-1;

  • 参数:

    • _key 为整型值,用户可以自己设定。有两种情况:
      • 键值是IPC_PRIVATE,该值通常为0,意思就是创建一个仅能被进程进程给我的信号量。
      • 键值不是IPC_PRIVATE,我们可以指定键值,例如1234;也可以一个ftok()函数来取得一个唯一的键值。
    • nsems 表示初始化信号量的个数。比如我们要创建一个信号量,则该值为1.,创建2个就是2。
    • semflg :信号量的创建方式或权限。有IPC_CREAT,IPC_EXCL。
      • IPC_CREAT如果信号量不存在,则创建一个信号量,否则获取。
      • IPC_EXCL只有信号量不存在的时候,新的信号量才建立,否则就产生错误。
  • semid=semget(MYKEY,1,IPC_CREAT|0666);//创建了一个权限为666的信号量
    

semctrl

  • #include<sys/sem.h>
    int semctl(int _semid ,int _semnum,int _cmd ……);
    
  • 功能:控制信号量的信息。

  • 返回值:成功返回0,失败返回-1;

  • 参数:

    • _semid 信号量的标志码(ID),也就是semget()函数的返回值;
    • semnum, 操作信号在信号集中的编号。从0开始。
    • _cmd 命令,表示要进行的操作。
  • 参数cmd中可以使用的命令如下:

    • IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
    • IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
  • IPC_RMID将信号量集从内存中删除。

    • GETALL用于读取信号量集中的所有信号量的值。
    • GETNCNT返回正在等待资源的进程数目。
  • GETPID返回最后一个执行semop操作的进程的PID。

  • GETVAL返回信号量集中的一个单个的信号量的值。

  • GETZCNT返回这在等待完全空闲的资源的进程数目。

  • SETALL设置信号量集中的所有的信号量的值。

  • SETVAL设置信号量集中的一个单独的信号量的值。

  • Semunion ;第4个参数是可选的;semunion :是union semun的实例。

  • * union semun {
      int  val;
      struct  semid_ds *buf;
      unsigned short  *arrary;
    };
    

semop

  • sembuf

    • struct sembuf{
      	short sem_num;
      	short sem_op;
      	short sem_flg;
      };
      
    • sem_num是信号量的编号,如果你的工作不需要使用一组信号量,这个值一般就取为0

    • sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值,一个是“-1”,也就是P操作,等待信号量变得可用;另一个是“+1”,也就是我们的V操作,发出信号量已经变得可用

    • sem_flag通常被设置为SEM_UNDO.她将使操作系统跟踪当前进程对该信号量的修改情况

  • semop

    • int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
      
    • 作用是改变信号量的值

sem_post and sem_wait

  • sem_post函数(函数原型 int sem_post(sem_t *sem);)
    • 作用是给信号量的值加上一个“1”。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是有线程的调度策略决定的。
  • sem_wait函数(函数原型 int sem_wait(sem_t * sem);)
    • 它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。

进程

fork

  • 用于创建一个新进程,称为子进程

    pid_t fork( void);
    
  • (pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中)

  • 返回值: 若成功调用一次则返回两个值,

    • 子进程返回0
    • 父进程返回子进程ID;
    • 否则,出错返回-1

信号量和互斥锁的区别与联系

  • 互斥锁(Mutex)保证了使用资源线程的唯一性和排他性,但是无法限制资源释放后其他线程申请的顺序问题,所以是无序的。
  • 信号量(Semaphore)一般就是互斥的(少许情况读取是可以同时申请的),其保证了线程执行的有序性,可以理解为从一到多的进步,像比较有名的理发厅问题,我们就需要设一个Integer而非Boolean,因为理发厅里面的座椅不可能只有一张。
  • 互斥锁必须由单个线程获取和释放。
  • 信号量是由单个线程释放,另一个线程获取,保证线程同步。
  • 信号量是互斥的进步,Semaphore=1时可以看成互斥锁。

生产者消费者问题

理发师问题

  • 理发师问题的描述:
    • 一个理发店接待室有n张椅子,工作室有1张椅子;
    • 没有顾客时,理发师睡觉;第一个顾客来到时,必须将理发师唤醒;
    • 顾客来时如果还有空座的话,他就坐在一个座位上等待;
    • 如果顾客来时没有空座位了,他就离开,不理发了;
    • 当理发师处理完所有顾客,而又没有新顾客来时,他又开始睡觉。
  • img
  • img

读者-写者问题

  • 教材中对读者写者问题算法均有描述,但这个算法在不断地有读者流的情况下,写者会被阻塞。编写一个写者优先解决读者写者问题的程序,其中读者和写者均是多个进程,用信号量作为同步互斥机制。

  • 读者优先

  • 写者优先

    • //写者优先 
      int wcount = 0;  //用于记录写者数量 
      int rcount = 0;   //用于记录读者数量
      semaphore rmutex = 1;   //用于读者进程互斥修改rcount
      semaphore wmutex = 1;   //用于写者进程互斥修改wcount
      semaphore file = 1;    //用于读者写者互斥访问file 
      semphore  read = 1;     //用于阻塞读者进程,实现写者优先 
      
      writer()
      {
          P(wmutex);
          if(wcount == 0)
              P(read);
          wcount++;
          V(wmutex);    
          P(file);     //写者互斥访问文件 
          do_writing();
          V(file);
          P(wmutex)
          wcount--;
          if(wcount == 0)
              V(read);
          V(wmutex);
      } 
      
      reader()
      {
          P(read);     //检查写者队列是否为空。 
          P(rmutex);
          if(rcount == 0)
              P(file);   //申请文件资源 
          rcount++;
          V(rmutex);
          V(read); 
          do_reading();
          P(rmutex);
          rcount--;
          if(rcount == 0)
              V(file);
          V(rmutex);    
      }
      
posted @ 2020-11-27 16:39  xxxuanei  阅读(170)  评论(0编辑  收藏  举报