linux系统编程—信号量

信号量描述

信号量和信号完全不同,虽然它们只相差一个字。管道、消息队列、共享内存、信号都可以携带消息,而信号量不可以携带数据,那信号量的作用是什么?

以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。在此场景中,车位就是临界资源,而看门人就起信号量的作用。

临界资源:多道程序系统中存在许多进程,它们共享各种资源,然而有很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。许多物理设备都属于临界资源,如输入机、打印机、磁带机等。

信号量定义

最简单的信号量是一个只有0与1两个值的变量,二值信号量。这是最为通常的形式。具有多个正数值的信号量被称之为通用信号量。

P与V的定义出奇的简单。假定我们有一个信号量变量sv,两个操作定义如下:

P(sv)    如果sv大于0,减小sv。如果sv为0,挂起这个进程的执行。
V(sv)    如果有进程被挂起等待sv,使其恢复执行。如果没有进行被挂起等待sv,增加sv。

在信号量进行PV操作时都为原子操作(因为它需要保护临界资源)

注:原子操作:单指令的操作称为原子的,单条指令的执行是不会被打断的

semget函数

用于创建信号量

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

int semget(key_t key,int nsems,int flags)

key:信号量键值,可以理解为信号量的唯一性标记。
num_sems:信号量的数目,一般为1
sem_flags:有两个值,IPC_CREATE和IPC_EXCL,
IPC_CREATE表示若信号量已存在,返回该信号量标识符。
IPC_EXCL表示若信号量已存在,返回错误。

返回值:相应的信号量标识符,失败返回-1

semop函数

用于修改信号量的值

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

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

sem_id:信号量标识符

nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作

sembuf的定义如下:

struct sembuf{ 
    short sem_num;   //除非使用一组信号量,否则它为0 
    short sem_op;   //锁加一或者减一                                      
    short sem_flg; //通常为SEM_UNDO,使操作系统跟踪信号量, 
                  //并在进程没有释放该信号量而终止时,操作系统释放信号量 
}; 

semctl函数

用于信号量的初始化和删除

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

int semctl(int semid, int semnum, int cmd, ...);//参数...是不是下了一跳

sem_id:是由semget返回的信号量标识符

semnum:当前信号量集的哪一个信号量

cmd:有两个值SETVAL,IPC_RMID,分别表示初始化和删除信号量(删除的话就不需要缺省参数,只需要三个参数即可)。

如有需要第四个参数一般设置为union semnu arg;定义如下

union semun
{ 
    int val;  //使用的值
    struct semid_ds *buf;  //IPC_STAT、IPC_SET 使用的缓存区
    unsigned short *arry;  //GETALL,、SETALL 使用的数组
    struct seminfo *__buf; // IPC_INFO(Linux特有) 使用的缓存区
};//一般用到的是val,表示要传给信号量的初始值。

代码实现

利用信号量让子进程先运行 放锁之后父进程再运行

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.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) */
};

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("getkey\n");
}

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 the key\n");
}

int main(int argc, char const *argv[])
{
    key_t key;
    int semid;

    key = ftok(".",2);
    //1是信号量的个数
    semid = semget(key, 1, IPC_CREAT|0666);//获取/创建信号量

    union semun initsem;
    initsem.val = 0;
    //操作第0个信号量   
    semctl(semid, 0, SETVAL, initsem);//初始化信号量
    //SETVAL设置信号量的值 设置为initsem

    int pid = fork();
    if(pid > 0){
        //父进程拿锁 没锁等待
        pGetKey(semid);
        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;
}

编译运行

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些值得推荐的Linux系统编程书籍: 1.《Linux系统编程手册》(Linux System Programming):Michael Kerrisk所著的这本书是学习Linux系统编程的绝佳入门书籍,它涵盖了Linux系统编程的所有基础知识,包括进程管理、文件I/O、信号处理、线程、进程间通信等。此外,该书还提供了大实例代码和实践操作,可以帮助读者更好地理解Linux系统编程的重要概念和技术。 2.《UNIX环境高级编程》(Advanced Programming in the UNIX Environment):这是一本经典的UNIX系统编程书籍,由W. Richard Stevens所著。该书详细介绍了UNIX系统编程的各个方面,包括进程、信号、进程间通信、文件I/O、网络编程等。该书还提供了大实例和代码,以及详细的注释和解释,可以帮助读者深入理解UNIX系统编程的各个方面。 3.《UNIX网络编程》(UNIX Network Programming):这是另一本UNIX系统编程的经典书籍,由W. Richard Stevens所著。该书介绍了UNIX网络编程的各个方面,包括套接字编程、进程间通信、网络协议、TCP/IP协议等。该书提供了大实例和代码,可以帮助读者深入理解UNIX网络编程的各个方面。 4.《深入理解Linux内核》(Understanding the Linux Kernel):这是一本关于Linux内核的详细介绍和解释的书籍,由Daniel P. Bovet和Marco Cesati所著。该书介绍了Linux内核的各个方面,包括进程管理、内存管理、文件系统、设备驱动程序等。该书提供了大的实例和代码,可以帮助读者深入理解Linux内核的各个方面。 5.《Linux设备驱动程序》(Linux Device Drivers):这是一本关于Linux设备驱动程序的详细介绍和解释的书籍,由Alessandro Rubini和Jonathan Corbet所著。该书介绍了Linux设备驱动程序的各个方面,包括字符设备、块设备、网络设备等。该书提供了大的实例和代码,可以帮助读者深入理解Linux设备驱动程序的各个方面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值