信号量集与共享内存
今日练习:设计一个程序,作为进程A,进程A专门创建一个信号量集,要求信号量集中有1个信号量,对信号量集合中的信号量进行设置,要求集合中的信号量的初值为1,然后再设计2个程序,分别是进程B和进程C,要求进程B和进程C使用进程A创建的信号量集合中的信号量实现互斥访问。 提示:进程A、进程B、进程C需要使用共享内存作为临界资源的访问。
1.我们在使用信号量集函数接口前首先得了解其中的结构体,如下
struct sembuf
{
unsigned short sem_num;
short sem_op;
short sem_flg;
}
1.1 semb.sem_num = 0,sem_num成员指的是信号量集中的信号量元素的下标,通过可以访问信号量集中的某个信号量,就相当于可以访问某种公共资源
1.2 semb.sem_op = -1,semb.sem_op成员指的是对选中的信号量的操作,常见的操作就是P/V操作,如果该成员是正整数,则表示释放信号量,相当于完成V操作。如果该成员是负整数则表示申请信号量,相当于完成P操作。如果该成员的值为0时,就称为等零操作,即阻塞等待直到对应的信号量元素的值为零
1.3 semb.sem_flg成员指的是操作的标志位,常见的标志位有IPC_NOWAIT和SEM_UNDO,不设置的话可以为0
2.创建好一个信号量集之后,用户就可以对信号量集中的信号量资源进行PV操作,Linux系统提供了一个名字叫做semop()的函数,用户通过该函数可以实现对信号量进行申请或者释放。
目录进程A
/*****************************************************************
*
* file name :main.c
* authour :[email protected]
* date :2024.05.28
* function :设计一个函数,用于创建一个共享内存以及一个信号量集。
* note :为防止重复创建,需要先判断共享内存和信号量集是否存在。
* CopyRight (c) 2024 [email protected] All Right Reseverd
*
******************************************************************/
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// 定义信号量联合体
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 shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
shm_id = shmget(ftok(".",6),512,0644);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
}
// 映射共享内存
int *shmmp = (int *)shmat(shm_id,NULL,0);
if((void *)-1 == shmmp)
{
fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
*shmmp = 0;
//创建一个信号集
int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
if(-1 == sem_id)
{
fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
printf("sem_id = %d\n",sem_id);
union semun semn; //定义一个信号量联合体 变量
semn.val = 1; //将信号量联合体中的val的值赋值为1
semctl(sem_id,0,SETVAL,semn); //通过semctl函数接口将信号量的值设为1
while(1)
sleep(1);
return 0;
}
Linux系统内核需要对创建成功的信号量集进行维护,所以会记录每个信号量集的属性和信息,Linux系统提供了一个名称叫做semctl()的函数接口,用户可以调用该函数接口来实现设置信号量集的属性、获取信号量集的属性、删除信号量集等操作
进程B
设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印。
/*****************************************************************
*
* file name :main.c
* authour :[email protected]
* date :2024.05.28
* function :设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印。
* note :为防止重复创建,需要先判断共享内存和信号量集是否存在。
* CopyRight (c) 2024 [email protected] All Right Reseverd
*
******************************************************************/
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/*1.semb.sem_num = 0 sem_num成员指的是信号量集中的信号量元素的下标,
*通过可以访问信号量集中的某个信号量,就相当于可以访问某种公共资源,semb.sem_op = -1
*2.semb.sem_op成员指的是对选中的信号量的操作,常见的操作就是P/V操作,如果该成员是正整数,则表示释放信号量,
*相当于完成V操作。如果该成员是负整数则表示申请信号量,相当于完成P操作。如果该成员的值为0时,就称为等零*
*操作,即阻塞等待直到对应的信号量元素的值为零
*3.semb.sem_flg成员指的是操作的标志位,常见的标志位有IPC_NOWAIT和SEM_UNDO,不设置的话可以为0
*/
int p(int sem_id,int sem_num)
{
struct sembuf semb = {sem_num,-1,0};
semop(sem_id,&semb,1);
}
int v(int sem_id,int sem_num)
{
struct sembuf semb = {sem_num,1,0};
semop(sem_id,&semb,1);
}
int main()
{
// 创建共享内存对象
int shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
shm_id = shmget(ftok(".",6),512,0644);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
}
// 映射共享内存
int *shmmp = (int *)shmat(shm_id,NULL,0);
if((void *)-1 == shmmp)
{
fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
if(-1 == sem_id)
{
fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
printf("%d\n",shmmp[0]);
//对共享内存的操作是先加锁,再解锁,更像是标志位-1为p操作,1是v操作
while(1)
{
//p操作是原子操作无法打断,且当进行p操作时,sembuf结构体中的sem_op成员的值必须为-1
p(sem_id,0);
// (*shmmp) = (*shmmp) + 1; //当p操作时,所以需要先加锁,再进行对共享内存的操作,将共享内存内的值加一
// printf("%d\n",shmmp[0]);
//v操作是原子操作无法打断,且当进行v操作时,sembuf结构体中的sem_op成员的值必须为1
v(sem_id,0);
(*shmmp) = (*shmmp) + 1; //当v操作时,所以需要先解锁,再进行对共享内存的操作,将共享内存内的值加一
sleep(3);
printf("%d\n",shmmp[0]);
}
return 0;
}
进程C
设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印同时观看进程B打印出来的内容观察p/v操作的效果。
/*****************************************************************
*
* file name :main.c
* authour :[email protected]
* date :2024.05.28
* function :设计一个函数,用于打开一个共享内存以及一个信号量集,并进行p/v操作,每次操作后对共享内存内的值加一,并打印同时观看semb函数打印出来的内容观察p/v操作的效果。
* note :为防止重复创建,需要先判断共享内存和信号量集是否存在。
* CopyRight (c) 2024 [email protected] All Right Reseverd
*
******************************************************************/
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/msg.h>
#include <features.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int p(int sem_id,int sem_num)
{
struct sembuf semb = {sem_num,-1,0};
semop(sem_id,&semb,1);
}
int v(int sem_id,int sem_num)
{
struct sembuf semb = {sem_num,1,0};
semop(sem_id,&semb,1);
}
int main()
{
char num[100];
// 创建共享内存对象
int shm_id = shmget(ftok(".",6),512,0644|IPC_CREAT|IPC_EXCL);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
shm_id = shmget(ftok(".",6),512,0644);
if(-1 == shm_id)
{
fprintf(stderr,"shmget error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
}
// 映射共享内存
int *shmmp = (int *)shmat(shm_id,NULL,0);
if((void *)-1 == shmmp)
{
fprintf(stderr,"shmat error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
int sem_id = semget(ftok(".",6),1,0644|IPC_CREAT);
if(-1 == sem_id)
{
fprintf(stderr,"sem error,errno:%d,%s\n",errno,strerror(errno));
return -1;
}
while(1)
{
//p操作是原子操作无法打断,且当进行p操作时,sembuf结构体中的sem_op成员的值必须为-1
p(sem_id,0);
// (*shmmp) = (*shmmp) + 1; //当p操作时,所以需要先加锁,再进行对共享内存的操作,将共享内存内的值加一
// printf("%d\n",shmmp[0]);
//v操作是原子操作无法打断,且当进行v操作时,sembuf结构体中的sem_op成员的值必须为1
v(sem_id,0);
(*shmmp) = (*shmmp) + 1; //当v操作时,所以需要先解锁,再进行对共享内存的操作,将共享内存内的值减一
sleep(3);
printf("%d\n",shmmp[0]);
}
return 0;
}
标签:共享内存,errno,信号量,sem,include,id
From: https://www.cnblogs.com/xiaobaibudongjiuwen/p/18218779