• Linux--信号量


    一、信号量
    信号量(semaphore)与已经介绍过的IPC结构不同,他是一个计数器。
    用于实现进程间的互斥与同步,而不是用于存储进程间的通信数据。
    可以与共享内存配合使用。
    临界资源: 多道程序系统种存在许多进程,他们共享各种资源,然而有很多资源一次智能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。许多物理设备都属于临界资源,如输入机、打印机、磁带机等。
    信号量集: 相当于信号量的集合。
    P V 操作 P拿取,V放回
    1、特点:
    ①、信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
    ②、信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作。
    ③、每次对信号量的PV操作不仅限于对信号量加 1 或减 1 ,而且可以加减任意正整数。
    ④、支持信号量组

    2、原型:
    Linux下信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。

    #include 
     
    //创建或获取一个信号量组:若成功返回信号量级ID,失败返回-1
    int semget(key_t key, int num_sems, int sem_flags);
    //对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
    int semop(int semid, struct sembuf semoparray[], size_t numops); 
    //3.控制信号量的相关信息
    int semctl(int semid, int sem_num, int cmd, ...);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、例:

    //信号量
    
    /*
    #include 
    #include 
    #include 
     
    //       int semget(key_t key, int nsems, int semflg);
    //       int semctl(int semid, int semnum, int cmd, ...);
    
    struct sembuf
    {
        short sem_num;
        short sem_op;
        short sem_flg;
    }
    
    */
    
    #include 
    #include 
    #include 
    #include 
    
    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)*/
    }int main(int argc,char const *argv[])
    {
    	key_t key;
    	int semid;
    	
    	key = ftok(".",2);
    	
    	semid = semget(key,1,IPC_CREAT|0666);
    	//获取信号量(信号量中有一个合集)
    	
    	//定义一个联合体
    	union semun initsem;
    	initsem.val = 1;
    	
    	semctl(semid,0,SATVAL,initsem);
    	//做初始化信号量,操作第0个信号量,SATVAL设置信号量的值为initsem,
    
    
    	int pid = fork();
    	if(pid > 0){
    		printf("this is father\n");
    	}
    	else if(pid == 0){
    		printf("this is child\n");
    	}
    	else{
    		printf("fork error\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    此程序运行一般为父进程先运行,然后运行子进程。偶尔反转。

    修改程序,使信号量控制让子进程先运行:

    //修改程序,使信号量控制让子进程先运行:封装两个函数 P操作和 V操作
    
    /*
    #include 
    #include 
    #include 
     
    //       int semget(key_t key, int nsems, int semflg);
    //       int semctl(int semid, int semnum, int cmd, ...);
    //		 int semop(int semid, struct sembuf *sops, unsigned nsops); 
    struct sembuf short;
    {
        short.sem_num;
        short.sem_op;
        short.sem_flg;
    }
    
    */
    
    #include 
    #include 
    #include 
    #include 
    
    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)*/
    };
    
    //P操作
    void pGetKey(int id)
    {
    	struct sembuf set;
    
        set.sem_num = 0;
        set.sem_op = -1;
        set.sem_flg = SEM_UNDO;
    	semop(id,&set,1);
    	printf("get ket!\n");
    }
    
    
    //V操作
    void vPutBackKey(int id)
    {
    	struct sembuf set;
    
        set.sem_num = 0;
        set.sem_op = -1;
        set.sem_flg = SEM_UNDO;
    	semop(id,&set,1);
    	printf("put back ket!\n");
    }
    
    int main(int argc,char const *argv[])
    {
    	key_t key;
    	int semid;
    	
    	key = ftok(".",2);
    	
    	semid = semget(key,1,IPC_CREAT|0666);
    	//获取信号量(信号量中有一个合集)
    	
    	//定义一个联合体
    	union semun initsem;
    	initsem.val = 0;
    	
    	semctl(semid,0,SATVAL,initsem);
    	//做初始化信号量,操作第0个信号量,SATVAL设置信号量的值为initsem,
    
    
    	int pid = fork();
    	if(pid > 0){
    		pGetKey(ssemid);
    		printf("this is father\n");
    		vPutBackKey(semid);
    		semctl(semid,0,IPC_RMID);//销毁信号量
    	}
    	else if(pid == 0){
    		
    		printf("this is child\n");
    		vPutBackKey(semid);
    	}
    	else{
    		printf("fork error\n");
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
  • 相关阅读:
    VMWARE 服务器整合为战提供的解决方案
    Python文件操作和管理指南:打开、读取、写入和管理文件
    C# 要被淘汰了?!
    神经网络入门自学教程电子书,神经网络快速入门
    【进制转换】
    基于SSM+Vue的鲸落文化线上体验馆设计与实现
    mysql group_concat and laravel group_concat使用
    UEFI统一可扩展固件接口
    抖音如何推广引流?抖音推广引流的经验与工具分享
    C. Queries for the Array
  • 原文地址:https://blog.csdn.net/weixin_48208102/article/details/132940525