(P30)system v信号量

1.信号量

  • 信号量和P,V原语由Dijkstra提出
  • 信号量
    (1)互斥问题: P,V在同一个进程中
    (2)同步问题:P,V在不同进程中
  • 信号量值含义,S表示计数值
    (1)S>0:S表示可用资源的个数
    (2)S=0:表示无可用资源,无等待进程
    (3)S<0:|S|表示等待队列中进程个数,即:若当前资源计数值S=0,此时来一个进程申请资源,计数值减去1为-1,|-1|=1表示等待队列中的进程个数为1
  • 信号量数据结构
struct semaphore
{
	int value;//信号量计数值S
	pointer_PCB queue;//将等待进程的控制块指针放到等待队列中
}
  • P原语:进程申请资源
    原语:这块代码是原子性的,不会被其它信号所中断,在硬件上,实际是通过关闭中断的方式来实现的。
P(s)
{
	s.value=s.value--;
	if (s.value<0)
	{
		该进程状态置为等待状态;
		将该进程的PCB插入相应的等待队列s.queue末尾
	}
}
  • V原语:进程归还资源
    若之前s.value<0说明有进程在等待资源,此时s.value++归还一个资源,意味着要唤醒一个进程
V(s)
{
	s.value=s.value++;
	if (s.vaue <=0)
	{
		唤醒相应等待队列s.queue中等待的一个进程,
		改变其状态为就绪态;
		并将其插入就绪队列中;
	}
}

2.信号量集结构

  • 信号量集结构struct semid_ds
struct semid_ds {
	//IPC对象都有的
    struct ipc_perm sem_perm;  /* Ownership and permissions */
	
	//信号量集所特有
    time_t          sem_otime; /* Last semop time *///最后一次执行PV操作的时间
    time_t          sem_ctime; /* Last change time *///信号量集最后一个改变的时间
    unsigned long   sem_nsems; /* No. of semaphores in set *///信号量集中的信号量的个数
};

3.信号量集函数

  • 消息队列和共享内存有4个,而信号量集只有三个,因为semop涵盖了P和V操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

//创建或者打开一个信号量集
int semget(key_t key, int nsems, int semflg);

//控制一个信号量集
int semctl(int semid, int semnum, int cmd, ...);

int semop(int semid, struct sembuf *sops, size_t nsops);
  • semget函数
功能:用来创建和访问一个信号量集

原型:
int semget(key_t key, int nsems, int semflg);

参数:
key:信号集的名字
nsems:信号集中信号量的个数
semflg:由9个权限标志构成,他们的用法和创建文件时使用的mode模式标志是一样的

返回值:
成功返回一个非负整数,即:该信号集的标识码;
失败返回-1
  • shmctl函数
功能:用于控制信号量集

原型:
int semctl(int semid, int semnum, int cmd, ...);

参数:
semid:由semget返回的信号集标识码
semnum:信号集中信号量的序号
cmd:将要采取的动作(3)
最后一个参数根据命令不同而不同

返回值:
成功返回0;
失败返回-1
  • cmd
    在这里插入图片描述
  • eg:权限perms是666,信号量集中信号量的个数nsems为1
    在这里插入图片描述
删除信号量集:
ipcrm -S key,eg:ipcrm -S 0x4d2
ipcs -Q semid
  • eg:NetworkProgramming-master (1)\NetworkProgramming-master\P30sem.cpp
/
// Created by wangji on 19-8-13.
//

// p30 system v信号量(一)

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

// https://blog.csdn.net/a1414345/article/details/64513946

#define ERR_EXIT(m) \
        do \
        { \
             perror(m); \
             exit(EXIT_FAILURE);    \
        } while (0);

//来自man semctl
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 sem_creat(key_t key)
{
    int semid;
    semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);//IPC_EXCL表示只能创建1次
    if (semid == -1)
    {
        ERR_EXIT("semget");
    }
    return semid;//返回信号量集的id
}

//仅仅打开一个创建的信号量集
int sem_open(key_t key)
{
    int semid;
    semid = semget(key, 0, 0);//由于信号量集已经存在了,可以不指定信号量的个数;打开选项也可以不必关心
    if (semid == -1)
    {
        ERR_EXIT("semget");
    }
    return semid;
}

// 设置信号量中信号量的值
int sem_setval(int semid, int val)
{
    union semun su;
    su.val = val;
    int ret;
    ret = semctl(semid, 0, SETVAL, su);
    if (ret == -1)
    {
        ERR_EXIT("setval")
    }
    return 0;
}

// 获取信号量中信号量的值
int sem_getval(int semid)
{
    int ret;
    ret = semctl(semid, 0, GETVAL,0);//第4个参数忽略了,填写0
    if (ret == -1)
    {
        ERR_EXIT("getval")
    }
    printf("sem.val = %d\n", ret);
    return ret;
}

//只能删除信号量集,不能删除信号量集中的某个信号量
int sem_d(int semid)
{
    int ret;
    ret = semctl(semid, 0, IPC_RMID, NULL);//信号量个数不知道的话填写0
    if (ret == -1)
    {
        ERR_EXIT("rm_sem")
    }
    return 0;
}

int main(int argc, char** argv)
{
    int opt;
   
    int semid;
    semid=sem_creat(1234);
    sleep(5);//过5s删除该信号量集
    sem_d(semid);
   
 }
  • 测试:执行:./sem,过5s后,执行ipcs发现信号量集会被删除
    在这里插入图片描述
    在这里插入图片描述

2902

4.信号量eg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章