Linux:浅谈信号量

1.信号量的概念。
信号量的本质是一种数据操作锁,它本⾝身不具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信,它本⾝身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能。
当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,等于0,无资源可用,进程会进⼊入睡眠状态直至资源可用。
当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减
操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。
而在信号量的创建及初始化上,不能保证操作均为原子性。
2.信号量是如何工作的
由于信号量只能进⾏行两种操作等待和发送信号,即P(sv)和V(sv),他们的⾏行为是这样的:
P(sv):如果sv的值⼤大于零,就给它减1;如果它的值为零,就挂起该进程的执⾏行
V(sv):如果有其他进程因等待sv⽽而被挂起,就让它恢复运⾏行,如果没有进程因等待sv⽽而挂
起,就给它加1.
3.相关函数
 函数原型:int semget(key_t key,int nsems,int semflg);
 参数解释:
key:所创建或打开信号量集的键值。需要是唯一的非零整数。
  nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。几乎总是取值为1.
  flag:调用函数的操作类型,也可用于设置信号量集的访问权限,用或来表示。

  功能描述
  获取与某个键关联的信号量集标识。信号量集被建立的情况有两种:
  1.如果键的值是IPC_PRIVATE。
  2.或者键的值不是IPC_PRIVATE,并且键所对应的信号量集不存在,同时标志中指定IPC_CREAT。
  当调用semget创建一个信号量时,他的相应的semid_ds结构被初始化。ipc_perm中各个量被设置为相应
  值:
  sem_nsems被设置为nsems所示的值;
  sem_otime被设置为0;
  sem_ctime被设置为当前时间。
函数原型:int semop( int semid, struct sembuf semoparray[], size_t nops );
参数解释:
参数semid是一个通过semget函数返回的一个信号量标识符
参数nops标明了参数semoparray所指向数组中的元素个数
参数semoparray是一个struct sembuf结构类型的数组指针,
结构sembuf来说明所要执行的操作,其成员如下:
这里写图片描述
其中sem_flg说明函数semop的行为。通常被设置为SEM_UNDO。它将使得操作系统跟着当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量。

函数原型:int semctl(int semid,int semnum,int cmd,…);
参数解释:
sem_id是由semget返回的信号量标识符。
sem_num与前面一个函数相同。
cmd:表示将要采取的动作。
如果有第四个参数,一般为联合体semun,成员如下:
这里写图片描述

信号量使用的简单示例:
我们创建一个进程,代码如下:

#include"head.h"
#include<unistd.h>
#include<sys/wait.h>
int main(){

    int sem_id = my_semget(1);
    initial(sem_id, 0);
    pid_t id = fork();//创建一个子进程
    if (0 == id){
       while(1){ 
       //上锁
       if ( sem_p(sem_id, 0) == -1){
            perror("children p error");
           exit(0);
       }
        usleep(10200);
        printf("A");
        fflush(stdout);
        usleep(23043);
        printf("A");
        fflush(stdout);
       if ( sem_v(sem_id,0) == -1){
            perror("children v error");
           exit(0);
       }
    }
    }
    else{

     while(1){ 
     //上锁
       if ( sem_p(sem_id, 0) == -1){
            perror("father   p error");
           exit(0);
       }
        usleep(10200);
        usleep(16200);
        printf("B");
        fflush(stdout);
        usleep(33043);
        printf("B");
        fflush(stdout);
       if ( sem_v(sem_id,0) == -1){
            perror("father   v error");
           exit(0);
       }
    }

        int stat = 0;
        wait(&stat);
    }

}

在没有信号量之前,因为有睡眠延时,系统会随机打印A和B,如:
这里写图片描述
添加信号量之后,因为A进程在信号量上锁后,sv值变为0,则B进程会挂起,直到A进程解锁,则系统会有规律的打印A和B。
这里写图片描述

head.h:
#ifndef _HEAD_
#define _HEAD_
#include<stdio.h>
#include<stdlib.h>
#include<sys/sem.h>
#include<sys/types.h>
#include<sys/ipc.h>

#define _PATH "."
#define _NUM 0x98
union semun {
    int val; // 使⽤用的值
    struct semid_ds *buf; // IPC_STAT、IPC_SET 使⽤用缓存区
    unsigned short *array; // GETALL,、SETALL 使⽤用的数组
    struct seminfo *__buf; // IPC_INFO(Linux特有) 使⽤用缓存区
};


int my_semget(int sem_num);
int getsem();
int  initial(int sem_id, int which);
int sem_p(int sem_id, int which);
int sem_v(int sem_id, int which);
int destroy(int sem_id);

#endif

head.c:
#include "head.h"
#include<string.h>
int static semgeting(int sem_num, int flag){

    key_t key = ftok(_PATH, _NUM);
    return semget(key,sem_num, flag);
}

int static op_chang(int sem_id, int which, int op){
    sembuf sem_t;
    memset(&sem_t, 0, sizeof(sembuf));
    sem_t.sem_num = which;
    sem_t.sem_op  = op;
    sem_t.sem_flg = 0;
    return semop(sem_id, &sem_t,1);
}
int my_semget(int sem_num){

    return semgeting(sem_num, IPC_CREAT|IPC_EXCL|0666);
}
int getsem(){
    return semgeting(0, 0);
}
int  initial(int sem_id, int which){
    semun sem_t;
    sem_t.val = 1;
   return semctl(sem_id, which, SETVAL, sem_t);

}
int sem_p(int sem_id, int which){
    sembuf sem_t;
    return op_chang(sem_id, which,-1); 


}
int sem_v(int sem_id, int which){
    return op_chang(sem_id, which, 1); 
}
int destroy(int sem_id){
    return semctl(sem_id, 0, IPC_RMID, NULL);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值