• 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);    
        }
        
  • 相关阅读:
    oracle中job定时调用存储过程的实例
    oracle recyclebin详解(闪回删除的表)
    启动和禁用约束及删除违反约束的记录
    儒轩画的老鼠
    SQLServer2005重建索引
    [转]你真的了解 console 吗
    [转]C# 理解lock
    [转]大话 程序猿 眼里的 高并发
    莆田系医院名单
    .Net WEB 程序员需要掌握的技能
  • 原文地址:https://www.cnblogs.com/xuwanwei/p/14031114.html
Copyright © 2020-2023  润新知