计算机操作系统--信号量实验

信号量实验

  • 1、键值的创建与解释
  • 2、生成信号量
  • 3、初始化信号量和PV操作

1、键值的创建与解释

#include 
#include 
#include 
#include 

int main(){
        int x;
        x = ftok("/",1);  //在根目录下创建一个ID为1的键值
        printf("x = %p\n",x);

} 

输出后可以通过“ipcs -s”命令查看是否生成了信号量,ipcs是用于报告进程间通信机制状态的命令。它可以查看**共享内存(-m)、消息队列(-q)、信号量(-s)**等各种进程间通信机制的情况

同样可以使用“ipcrm -s semaphore”来删除信号量集

(此时使用该命令并没有信号量,因为还未使用semget函数生成信号量,仅仅是创建了一个键值)

2、生成信号量

#include 
#include 
#include 
#include 

int main(){

        int x,y;
        x = 0x1010002;//(其实是由上一个c语言执行文件创建的键值)
        printf("x = %p\n",x);
        y = semget(x,1,0666|IPC_CREAT);//参数:键值;nsems:需要创建的信号量数目;IPC_CREAT创建新的信号量集,即使已经存在(IPC_EXCL创建一个新的唯一的信号量集)
        if(y<0){
                perror("semget error");
        }
        printf("y = %d\n",y);

}

3、初始化信号量和PV操作

函数原型 int semctl(int semid, int semnum, int cmd, union semun arg)
函数传入值 semid:semget()函数返回的信号量集IPC标识符

semnum:操作信号在信号量集中的编号,第一个信号量的编号为0,如果只有一个信号量,该值为0

cmd:指定对信号量的各种操作
IPC_SATA:获得该信号量的semid_ds结构,并存放在有arg的buf指向的semid_ds结构中
IPC_RMID:从系统中删除信号量集
SETVAL:将信号量集中某一信号设置为arg的val值
SETALL:设置信号量集中所有信号量的值
GETVAL:返回信号量集中的一个信号量的当前值
GETALL:读取信号量集中所有信号量的值
**arg:是union semun结构
union semun
{
int val; //信号量的初值,当cmd为setval时使用
struct semid_ds buf;
unsigned short array;
}
函数原型 int_semop(int semid, struct sembuf *sops, size_t nsops)
函数传入值 semid:semget()函数返回的信号量集IPC标识符
sops:指向信号量操作数组,一个数组包含以下成员
struct sembuf
{
short sem_num; //信号量编号,第一个信号量的编号为0,如果只有一个信号量,该值就为0
short sem_op; //信号量操作,取值为-1,则表示P操作,取值为1,则表示V操作
short sem_flg; //通常设置为SEM_UNDO,这样在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量}
返回值 成功:0
出错:-1

为使函数接口调用方便,将信号量的初始化和PV操作封装成二位单个信号量的几个基本函数

//信号量初始化(赋值)函数
int init_sem(int sem_id, int n, int init_value)
{
        union semun
        {
                int val;
                struct semid_ds *buf;
                unsigned short *array;
        };
        union semun sem_union;
        sem_union.val = init_value;    //init_value 为初始值
        if(semctl(sem_id,n,SETVAL,sem_union) == -1)
        {
                perror("Initialize semaphore");
                return -1;
        }
        return 0;
}


//从系统中删除信号量集的函数
int del_sem(int sem_id)
{
        if(semctl(sem_id,0,IPC_RMID,NULL) == -1)
        {
                perror("Delete semaphore");
                return -1;
        }
        return 0;
}


//P操作函数
int sem_p(int sem_id, int n)
{
        struct sembuf sem_b;
        sem_b.sem_num = n;  //单个信号量的编号如果为0,即信号量集中的第一个信号量
        sem_b.sem_op = -1;  //表示P操作
        sem_b.sem_flg = SEM_UNDO;  //系统会自动释放将会在系统中残留的信号量
        if(semop(sem_id, &sem_b, 1) == -1)
        {
                perror("P operation");
                return -1;
        }
        return 0;
}


//V操作函数
int sem_v(int sem_id, int n)
{
        struct sembuf sem_b;
        sem_b.sem_num = n;  //单个信号量的编号如果为0,即信号量集中的第一个信号量
        sem_b.sem_op = 1;  //表示V操作
        sem_b.sem_flg = SEM_UNDO;  //系统会自动释放将会在系统中残留的信号量
        if(semop(sem_id, &sem_b, 1) == -1)
        {
                perror("V operation");
                return -1;
        }
        return 0;

}

调用接口,实现资源同步问题的实现

#include 
#include 
#include 
#include 
#include 
#include 
#include "sem_com.c"
#define DELAY_TIME 3 //为了突出演示效果,等待几秒钟
int main(void)
{
        pid_t result;
        int sem_id;  //定义信号量集的ID号
        sem_id = semget(ftok("/",1),1,0666|IPC_CREAT);
        init_sem(sem_id,0,0); //初始化信号量,因为为同步问题,所以初始值设置为0
        //调用fork函数创建子进程
        result = fork();
        if(result == -1)
        {
                perror("Fork\n");
        }
        else if(result == 0)  //返回值为0代表子进程,在子进程中直接运行程序,最后调用V操作释放资源
        {
                printf("Child process will wait for some seconds...\n");
                sleep(DELAY_TIME);
                printf("The returned value is %d,in the child process(PID = %d)\n",result,getpid());
                sem_v(sem_id,0);
        }
        else
        {
                sem_p(sem_id,0);
                printf("The returned value is %d,in the father process(PID = %d)\n",result,getpid());
                del_sem(sem_id);
        }
        exit(0);
}

你可能感兴趣的:(计算机操作系统,开发语言,c语言)