系统5之信号量

概念:        

        信号灯(semaphore),也叫信号量。它是不同进程 间或一个给定进程内部不同线程间同步的机制。而是通过操作某些内容,达到控制另一进程 阻塞或释放 的操作 。系统5的信号量是由一个或多个信号灯组成的一个集合  其中每一个灯都是单独操作的。

目的:

        信号量是用来解决进程/线程之间同步或者互斥问题的一种通信机制,包括一个称为信号量的变量和该信号量下等待资源的进程等待列队。以及对信号量下进行的两个原子操作(PV)。其中,信号量对应于其中的一种资源,去一个非负数的整数。信号量---》资源个数,为0则没有可用资源。

操作:

        1、创建获取信号量

        2、PV操作

        3、删除信号量

API:

        创建函数:

semget:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);

功能:
    创建获取信号量
参数:
    1。密钥
    2。信号量个数
    3。semflg:IPC_CREAT|0666//权限

返回值:
    成功返回信号量ID
    失败返回-1,并设置错误码


密钥获取:
采用ftok函数
            #include <sys/types.h>
            #include <sys/ipc.h>
            key_t ftok(const char *pathname, int proj_id);
                  功能: 
                      手动创建或获取key 
                                    
                 参数: 
                      1>pathname:工程文件名(带路径)
                      2>proj_id :工程代号 
                                     
                 返回值: 
                       成功返回key 
                 失败返回-1,并设置错误码
                //只要参数不变化,总可以找到同一key

        PV操作:  

P操作:如果有可用资源(信号量值>0)则占用一个资源(信号量值-1,进入临界区代码)没有可用资源(信号值==0)则堵塞,直到系统分配资源给该任务(一直等待到有资源才会唤醒)。

V操作:如果该信号量的等待队列有任务在等待资源,则唤醒一个阻塞任务。如果没有任务等待,则释放一个资源(信号量-1)。

semop

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
    功能:     
         PV操作  
                            
    参数: 
         1>semid:信号量的ID  
         2>sops :struct sembuf * -->结构体指针 了解结构体
struct sembuf{
      unsigned short sem_num;  /* semaphore number */信号灯下标 
      short          sem_op;   /* semaphore operation */操作:+1 -1 +2 -2//PV操作 
      short          sem_flg;  /* operation flags */0可阻塞  IPC_NOWAIT不阻塞 
}

        3>nsops:结构体中利用到的灯的个数:要操作灯的个数 
        //使用PV操作,最好以一个灯的方式来操作
返回值:
    成功返回 0
    失败返回 -1,并设置错误码

      删除信号量:

        设置信号量,也可以说是初始化资源数

        通过value进行操作:查询,修改,删除

semctl 

#include <sys/types.h>
#include <sys/ipc.h>
include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
     功能: 
         对信号量的操作 
                            
     参数: 
           1>semid:信号量的ID  
           2>semnum:信号灯的下标 
           3>cmd:操作详情: 
                  IPC_RMID:删除信号量 
                  GETVAL:获取信号灯的Value值 
                  SETVAL:设置信号灯的Value值 
                                    
           4>...:根据操作详情而调用的值
                  IPC_RMID:NULL
                  GETVAL:  NULL
                  SETVAL: union semun --->联合体
      返回值: 
              GETVAL:成功获取vlaue值 
              其他成功返回0 
              失败返回-1,并设置错误码
                            
              返回值!=value值 
              查找value值:从灯提取value并替代返回值
              其他:函数直接返回
 union semun {
               int              val;    /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                          (Linux-specific) */
};

 如何在系统中查看信号量
            ipcs -s

  如何删除信号量 
            ipcrm -s 信号量ID

简单示例:

semget1.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
 union semun {
               int              val;    /* Value for SETVAL *///设置value值
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                          (Linux-specific) */
};
           
int main(){
    //1>创建或获取信号量 
        //前提:制作key  
        key_t key=ftok("1.c",1);
        if(key<0){
            perror("ftok");
            return -1;
        }
        printf("key为%#x\n",key);
        
        //创建或寻找到信号量 
        int semid=semget(key,3,IPC_CREAT|0666);
        if(semid<0){
            perror("semget");
            return -1;            
        }
        printf("信号量的ID:%d\n",semid);
        
    //操作:查询vlaue值 
    int val=semctl(semid,0,GETVAL,NULL);
    if(val<0){
            perror("semctl1");
            return -1; 
    }
    printf("val:%d\n",val);
    /*
    //2>对信号灯进行操作:P操作 
        struct sembuf light1={0,-4,0};//给结构体变量赋值 : 0号灯  -2操作  阻塞 
        int ret=semop(semid,&light1,1);//进程在此处因为0号灯 -2操作,导致阻塞 
        if(ret<0){
            perror("semop");
            return -1;
        }
        printf("test。。。\n");
    */
    //操作:设置value值
    union semun us;
    us.val=5;
    int ret=semctl(semid,0,SETVAL,us);
    if(val<0){
            perror("semctl2");
            return -1; 
    }
    
    //再次查询
    val=semctl(semid,0,GETVAL,NULL);
    if(val<0){
            perror("semctl3");
            return -1; 
    }
    printf("val:%d\n",val);
    
    return 0;
}

semget2.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main(){
    //1>创建或获取信号量 
        //前提:制作key  
        key_t key=ftok("1.c",1);
        if(key<0){
            perror("ftok");
            return -1;
        }
        printf("key为%#x\n",key);
        
        //创建或寻找到信号量 
        int semid=semget(key,3,IPC_CREAT|0666);
        if(semid<0){
            perror("semget");
            return -1;            
        }
        printf("信号量的ID:%d\n",semid);
        
    //2>对信号灯进行操作:V操作 
        struct sembuf light1={0,-1,0};//给结构体变量赋值 : 0号灯  -2操作  阻塞 
        int ret=semop(semid,&light1,1);//进程在此处因为0号灯 -2操作,导致阻塞 
        if(ret<0){
            perror("semop");
            return -1;
        }
        printf("疯狂星期四,不吃的话我真的会谢好吗\n");
    
    
    
    return 0;
}

通过semget阻塞1的运行。

猜你喜欢

转载自blog.csdn.net/apple_71040140/article/details/132514842