系统编程-信号量集

信号量集

目录

信号量集

引入

使用信号量集的步骤

1、获取键值

2、创建或获取信号量集的 id

3、对信号量的值进行初始化

4、对信号量进行操作

5、实例1:信号量集与共享内存

6、实例2:一个进程写,两个进程读,奇数次写的时候,进程A读,偶偶数次写的时候,进程B读


引入

  • 信号量集,就是由多个信号量组成的一个数组

信号量 可以当作一个指示灯,可以为进程提供一个同步机制
信号量就是一个值,整数值,可以进行"加减操作",但是减操作只能减到 0

-- 对信号量进行减操作 就是对信号量进行抢占的过程

  • 减操作成功 当前进程使用该资源 独占该资源
  • 减操作阻塞 表示其他进程正在使用该资源

-- 对信号量进行加操作 就是对信号量进行还原的过程

  • 加操作成功 表示当前进行对该资源进行释放

-- 我们可以使用信号量来实现进程对资源独占

使用信号量集的步骤

alt text

1、获取键值

(1)函数获取:

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/ipc.h>

-- 函数原型

  • key_t ftok(const char *pathname, int proj_id)

-- 函数的作用:

  • 通过传入的参数来获取指定的键值(ftok的两个参数一样,获取的键值就一样)

-- 函数的参数:

  • pathname:必须是存在的路径
  • proj_id:0~255

-- 函数的返回值:

  • 会根据函数的参数来返回一个键值

alt text

(2)自己定义:

  • #define my_key 0x12345678

-- 键值的作用:

  • 一样的键值可以让不同进程来获取到同一个消息队列的id号
  • 一个键值对应一个id号,是一一对应的。具有唯一性。

2、创建或获取信号量集的 id

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/sem.h>

-- 函数原型

  • int semget(key_t key, int nsems, int semflg)

-- 函数的作用:

  • 通过传入的键值来获取信号量集的id号
  • 创建一个信号量集出来,或者获取已有信号量集id号

-- 函数的参数:

  • key:键值
  • nsems:信号量的个数 (创建的信号量数组大小)
  • semflg:权限
    -- 固定填 IPC_CREAT | 0666

-- 函数的返回值:

  • 成功:信号量集的id号
  • 失败:-1

-- 创建成功可以通过指令来进行查看

  • ipcs -s

alt text

-- nsems:表示该信号量集中有几个元素

3、对信号量的值进行初始化

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/sem.h>

-- 函数原型

  • int semctl(int semid, int semnum, int cmd, ... /* union semun arg */)

-- 函数的作用:

  • 对信号量集的值进行初始化

-- 该函数由三个参数和四个参数的版本 取决于 cmd 而定 

alt text

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) */
           };

  • 当 cmd 为 SETVAL、 GETALL、 SETALL 的时候需要第四个参数

-- 对信号量集进行多种操作

  • 比如:1 获取信号量集中某个信号量的值
  • 2 获取该信号量集中的所有信号量值
  • 3 给信号量集中某个信号量进行赋值
  • 4 给所有信号量进行赋值
  • 5 删除信号量集

-- 函数的参数:

  • semid:信号量集的id号(要对哪一个信号量集进行操作)
  • semnum:信号量集中的第几个信号量

填写 元素的下标
比如: 第一个元素 填写 0
第三个元素填写 2
该参数的范围由信号量集的大小而定

  • cmd:要进行的具体的操作。

-- 函数的返回值:

  • 失败:-1
  • 成功返回一个正数,cmd 为 GETVAL 是返回信号量的值

-- cmd:要进行的具体的操作

  • GETVAL:获取单个信号量的值 不需要第四个参数
    该函数会返回第二个参数对应下标的信号量的值
    从函数的返回值来获取信号量的值

  • SETVAL:给单个的信号量进行赋值操作
    该参数会使函数需要第四个参数 我们需要自己定义在文件中

-- 将下面这个共用体定义在文件中即可
该参数会将第四个参数共用体中的 val 的值赋值给该信号量集中的第 semnum 个信号量

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) */
};

4、对信号量进行操作

-- 函数头文件

  • #include <sys/types.h>
  • #include <sys/ipc.h>
  • #include <sys/sem.h>

-- 函数原型

  • int semop(int semid, struct sembuf *sops, size_t nsops)

-- 函数的作用:

  • 对信号量进行操作(对信号量进行消耗(-1)和释放(+1))

-- 函数的参数:

  • semid:信号量集的id号
  • sops:对信号量的具体操作,对结构体赋值的方式。 

    alt text

struct sembuf{
        unsigned short sem_num;  /* semaphore number */
        short          sem_op;   /* semaphore operation */
        short          sem_flg;  /* operation flags */
};

sem_num:信号量的下标 要对哪一个信号量来进行操作
sem_op:要对信号量进行什么操作 +1 还原 -1 消耗
sem_flg:给 0 表示阻塞

  • nsops:同时操作几个信号量
  • -- 信号量操作的结构体数组的大小(如果只有一个信号量进行操作 给 1),如果是两个信号量,写2,三个写3

-- 函数的返回值:

  • 成功:0
  • 失败:-1

5、实例1:信号量集与共享内存

  • 两个进程 一个对共享内存进行写,一个对共享内存进行读,要求 第一个进程写一次 另一个进程读一次

-- 信号量只用初始化一次

  • ww.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>


#define key 0x12345678

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 shmid = shmget(key, 5, IPC_CREAT | 0666);
	if(shmid == -1)
	{
		perror("shmget()");
		return -1;
	}
	printf("创建共享内存成功!\n");
	
	char *p = shmat(shmid, NULL, 0);
	if(p ==(char *)-1)
	{
		perror("shmat");
		return -1;
	}
	printf("映射成功!\n");

	int semid = semget(key, 1, IPC_CREAT | 0666);
	if(semid == -1)
	{
		perror("semget()");
		return -1;
	}
	printf("创建信号量成功!\n");

	union semun sem;
	sem.val = 1;
	int sl = semctl(semid,0,SETVAL,sem);
	if(semid == -1)
	{
		perror("semctl()");
		return -1;
	}
	printf("初始化信号量成功!\n");

	struct sembuf sem_p={0,-1,0};
	struct sembuf sem_v={0,1,0};
	

	while(1)
	{
		semop(semid, &sem_p,1);
		printf("请输入数据:\n");
		scanf("%s",p);
		semop(semid, &sem_v,1);
	}

	// shmdt(p);
	// shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

  • rr.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>


#define key 0x12345678

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 shmid = shmget(key, 5, IPC_CREAT | 0666);
	if(shmid == -1)
	{
		perror("shmget()");
		return -1;
	}
	printf("创建共享内存成功!\n");
	
	char *p = shmat(shmid, NULL, 0);
	if(p ==(char *)-1)
	{
		perror("shmat");
		return -1;
	}
	printf("映射成功!\n");

	int semid = semget(key, 1, IPC_CREAT | 0666);
	if(semid == -1)
	{
		perror("semget()");
		return -1;
	}
	printf("创建信号量成功!\n");

	struct sembuf sem_p={0,-1,0};
	struct sembuf sem_v={0,1,0};
	

	while(1)
	{
		semop(semid, &sem_p,1);
		printf("接收到的数据为:%s\n",p);
		semop(semid, &sem_v,1);
	}

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

-- 运行结果

alt text

6、实例2:一个进程写,两个进程读,奇数次写的时候,进程A读,偶偶数次写的时候,进程B读

alt text


-- 分析

alt text

alt text

  • ww.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>


#define key 0x12345679

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 shmid = shmget(key, 5, IPC_CREAT | 0666);
	if(shmid == -1)
	{
		perror("shmget()");
		return -1;
	}
	printf("创建共享内存成功!\n");
	
	char *p = shmat(shmid, NULL, 0);
	if(p ==(char *)-1)
	{
		perror("shmat");
		return -1;
	}
	printf("映射成功!\n");

	int semid = semget(key, 2, IPC_CREAT | 0666);
	if(semid == -1)
	{
		perror("semget()");
		return -1;
	}
	printf("创建信号量成功!\n");

	union semun sem;
	sem.val = 1;
	int sl = semctl(semid,0,SETVAL,sem);
    semctl(semid,1,SETVAL,sem);
	if(sl == -1)
	{
		perror("semctl()");
		return -1;
	}
	printf("初始化信号量成功!\n");
    

	struct sembuf sem_p1 = {0,-1,0};
	struct sembuf sem_v1 = {0,1,0};

    struct sembuf sem_p2 = {1,-1,0};
	struct sembuf sem_v2 = {1,1,0};
	
    int num = 1;
    semop(semid, &sem_p1,1);

	while(1)
	{
        if(num%2 == 1)
        semop(semid, &sem_p2,1);
        else 
        semop(semid, &sem_p1,1);

        printf("请输入数据:\n");
        scanf("%s",p);

		if(num%2 == 1)
        semop(semid, &sem_v1,1);
		else
        semop(semid, &sem_v2,1);
		num ++;
		
	}

	// shmdt(p);
	// shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

  • rr1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>


#define key 0x12345679

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 shmid = shmget(key, 5, IPC_CREAT | 0666);
	if(shmid == -1)
	{
		perror("shmget()");
		return -1;
	}
	printf("创建共享内存成功!\n");
	
	char *p = shmat(shmid, NULL, 0);
	if(p ==(char *)-1)
	{
		perror("shmat");
		return -1;
	}
	printf("映射成功!\n");

	int semid = semget(key, 2, IPC_CREAT | 0666);
	if(semid == -1)
	{
		perror("semget()");
		return -1;
	}
	printf("创建信号量成功!\n");

	struct sembuf sem_p={0,-1,0};
	struct sembuf sem_v={0,1,0};
	

	while(1)
	{
		semop(semid, &sem_p,1);
		printf("接收到的数据为:%s\n",p);
		semop(semid, &sem_v,1);
	}

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

  • rr2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>


#define key 0x12345679

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 shmid = shmget(key, 5, IPC_CREAT | 0666);
	if(shmid == -1)
	{
		perror("shmget()");
		return -1;
	}
	printf("创建共享内存成功!\n");
	
	char *p = shmat(shmid, NULL, 0);
	if(p ==(char *)-1)
	{
		perror("shmat");
		return -1;
	}
	printf("映射成功!\n");

	int semid = semget(key, 2, IPC_CREAT | 0666);
	if(semid == -1)
	{
		perror("semget()");
		return -1;
	}
	printf("创建信号量成功!\n");

	struct sembuf sem_p={1,-1,0};
	struct sembuf sem_v={1,1,0};
	

	while(1)
	{
		semop(semid, &sem_p,1);
		printf("接收到的数据为:%s\n",p);
		semop(semid, &sem_v,1);
	}

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

alt text

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值