linux信号量

信号量(semaphore)本质是一个计数器,具有原子性,用于实现进程间的互斥与同步,不用于存储进程间数据。

目录

 

特点:

API:

调用顺序:

信号量集合的例子:


特点:

1,用于进程间同步,若要在进程间传递数据需要结合共享内存。

2,信号量基于PV操作。    ====》 什么是PV操作?

3,每次对信号量的PV操作不仅限于对信号量值+1或-1,而且可以加减任意正整数。

3,支持信号量组。

API:

0)数据结构

内核为每个信号量集合设置了一个semid_ds结构

struct semid_ds {
    struct ipc_permsem_perm ;
    structsem* sem_base ; //信号数组指针
    ushort sem_nsem ; //此集中信号个数
    time_t sem_otime ; //最后一次semop时间
    time_t sem_ctime ; //最后一次创建时间
} ;
每个信号量由一个无名结构表示,它至少包含下列成员: (这个是什么意思??)
struct {
    ushort_t semval ; //信号量的值
    short sempid ; //最后一个调用semop的进程ID
    ushort semncnt ; //等待该信号量值大于当前值的进程数(一有进程释放资源 就被唤醒)
    ushort semzcnt ; //等待该信号量值等于0的进程数
} ;

1)semget()函数,创建或获取一个信号量组。

int  semget(key_t key, int num_sems, int sem_flags);

返回值是一个称为信号量标识符的整数,semop和semctl函数将使用它。

参数nsem指定集合中的信号量数。(若用于访问一个已存在的集合,那就可以把该参数指定为0)

参数oflag可以是SEM_R(read)和SEM_A(alter)常值的组合。(打开时用到),也可以是IPC_CREAT或IPC_EXCL ;

semget并不初始化各个信号量的值,这个初始化必须通过以SETVAL命令(设置集合中的一个值)或SETALL命令(设置集合中的所有值) 调用semctl来完成。

2)semop()函数,对信号量组进行操作,改变信号量的值。

int semop(int semid, struct sembuf * opsptr , size_t numops);

struct sembuf{
    short sem_num;
    short sem_op;
    short sem_flg;
}

3)semctl()函数,控制信号量的相关信息。

int semctl(int semid, int sem_num, int cmd, ...);

cmd指定以下10中命令的一种,在semid指定的信号量组上执行此命令。

IPC_STAT   读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。

IPC_SET     设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。

IPC_RMID  将信号量集从内存中删除。

GETALL      用于读取信号量集中的所有信号量的值。

GETNCNT  返回正在等待资源的进程数目。

GETPID      返回最后一个执行semop操作的进程的PID。

GETVAL      返回信号量集中的一个单个的信号量的值。

GETZCNT   返回这在等待完全空闲的资源的进程数目。

SETALL       设置信号量集中的所有的信号量的值。

SETVAL      设置信号量集中的一个单独的信号量的值。

 

调用顺序:

需要5个元素。 一个用于初始化的联合体,初始化操作,P、V操作,删除操作。

#include <sys/sem.h>

//1, 用于semctl初始化的联合体
union semun{
    int                 val;
    struct    semid_ds *buf;
    unsigned short     *array;
};

//2, 初始化信号量
int init_sem(int sem_id, int value)
{
     union semun tmp;
     tmp.val = value;
     if(semctl(sem_id, 0, SETVAL, tmp) == -1)
     {
         perror("Init Semaphore Error");
         return -1;
     }
     return 0;
}
//3,
int sem_p(int sem_id)
{
/* 对信号量做减1操作,即等待P(sv)*/
    struct sembuf sbuf;
    sbuf.sem_num = 0;
    sbuf.sem_op = -1;        //P操作
    sbuf.sem_flg = SEM_UNDO;

    if(semop(sem_id, &sbuf, 1) == -1)
    {
        perror("P operation Error");
        return -1;
    }
    return 0;
}

//4,
int sem_v(int sem_id)
{
/* 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)*/
    struct sembuf sbuf;
    sbuf.sem_num = 0;
    sbuf.sem_op = 1;        //V操作
    sbuf.sem_flg = SEM_UNDO;

    if(semop(sem_id, &sbuf, 1) == -1)
    {
        perror("V operation Error");
        return -1;
    }
    return 0;
}
//5,
int del_sem(int sem_id)
{
    union semun tmp;
    if(semctl(sem_id, 0, IPC_RMID, tmp) == -1)
    {
        perror("Delete Semaphore Error");
        return -1;
    }
    return 0;
}

int main()
{
    int sem_id;  // 信号量集ID
    key_t key;  
    pid_t pid;

    // 获取key值
    if((key = ftok(".", 'z')) < 0)
    {
        perror("ftok error");
        exit(1);
    }

    // 创建信号量集,其中只有一个信号量
    if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1)
    {
        perror("semget error");
        exit(1);
    }

    // 初始化:初值设为0资源被占用
    init_sem(sem_id, 0);

    if((pid = fork()) == -1)
        perror("Fork Error");
    else if(pid == 0) /*子进程*/ 
    {
        sleep(2);
        printf("Process child: pid=%d\n", getpid());
        sem_v(sem_id);  /*释放资源*/
    }
    else  /*父进程*/
    {
        sem_p(sem_id);   /*等待资源*/
        printf("Process father: pid=%d\n", getpid());
        sem_v(sem_id);   /*释放资源*/
        del_sem(sem_id); /*删除信号量集*/
    }
    return 0;
}

 

 

信号量集合的例子:

原链接:https://www.cnblogs.com/fangshenghui/p/4039946.html  ;

代码:

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAX_SEMAPHORE 10
#define FILE_NAME "test2.c"
 
union semun{
    int val ;
    struct semid_ds *buf ;
    unsigned short *array ;
    struct seminfo *_buf ;
}arg;

struct semid_ds sembuf;
 
int main()
{
    key_t key ;
    int semid ,ret,i;
    unsigned short buf[MAX_SEMAPHORE] ;
    struct sembuf sb[MAX_SEMAPHORE] ;
    pid_t pid ;
 
    pid = fork() ;
    if(pid < 0)
    {
        /* Create process Error! */
        fprintf(stderr,"Create Process Error!:%s\n",strerror(errno));
        exit(1) ;
    }


   if(pid > 0)
   {
        /* in parent process !*/
        key = ftok(FILE_NAME,'a') ;
        if(key == -1)
        {
             /* in parent process*/
             fprintf(stderr,"Error in ftok:%s!\n",strerror(errno));
             exit(1) ;
        }
 
        semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666); //创建信号量集合
        if(semid == -1)
        {
            fprintf(stderr,"Error in semget:%s\n",strerror(errno));
            exit(1) ;
        }
        printf("Semaphore have been initialed successfully in parent process,ID is :%d\n",semid);
        sleep(2) ;
        printf("parent wake up....\n");
        /* 父进程在子进程得到semaphore的时候请求semaphore,此时父进程将阻塞直至子进程释放掉semaphore*/
        /* 此时父进程的阻塞是因为semaphore 1 不能申请,因而导致的进程阻塞*/
        for(i=0;i<MAX_SEMAPHORE;++i)
        {
            sb[i].sem_num = i ;
            sb[i].sem_op = -1 ; /*表示申请semaphore*/
            sb[i].sem_flg = 0 ;
        }
 
        printf("parent is asking for resource...\n");
        ret = semop(semid , sb ,10); //p()
        if(ret == 0)
        {
            printf("parent got the resource!\n");
        }
        /* 父进程等待子进程退出 */
        waitpid(pid,NULL,0);
        printf("parent exiting .. \n");
        exit(0) ;
    }
    else
    {
        /* in child process! */
        key = ftok(FILE_NAME,'a') ;
        if(key == -1)
        {
             /* in child process*/
             fprintf(stderr,"Error in ftok:%s!\n",strerror(errno));
             exit(1) ;
        }
 
        semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666);
        if(semid == -1)
        {
              fprintf(stderr,"Error in semget:%s\n",strerror(errno));
              exit(1) ;
        }
        printf("Semaphore have been initialed successfully in child process,ID is:%d\n",semid);
 
        for(i=0;i<MAX_SEMAPHORE;++i)
        {
             /* Initial semaphore */
             buf[i] = i + 1;
        }
    
        arg.array = buf;
        ret = semctl(semid , 0, SETALL,arg);
        if(ret == -1)
        {
             fprintf(stderr,"Error in semctl in child:%s!\n",strerror(errno));
             exit(1) ;
        }
        printf("In child , Semaphore Initailed!\n");
 
        /* 子进程在初始化了semaphore之后,就申请获得semaphore*/
        for(i=0;i<MAX_SEMAPHORE;++i)
        {
            sb[i].sem_num = i ;
            sb[i].sem_op = -1 ;
            sb[i].sem_flg = 0 ;
        }

        ret = semop(semid , sb , 10);//信号量0被阻塞
        if( ret == -1 )
        {
            fprintf(stderr,"子进程申请semaphore失败:%s\n",strerror(errno));
            exit(1) ;
        }

        printf("child got semaphore,and start to sleep 3 seconds!\n");
        sleep(3) ;
        printf("child wake up .\n");
        for(i=0;i < MAX_SEMAPHORE;++i)
        {
            sb[i].sem_num = i ;
            sb[i].sem_op = +1 ;
            sb[i].sem_flg = 0 ;
        }

        printf("child start to release the resource...\n");
        ret = semop(semid, sb ,10) ;
        if(ret == -1)
        {
            fprintf(stderr,"子进程释放semaphore失败:%s\n",strerror(errno));
            exit(1) ;
        }
    
        ret = semctl(semid ,0 ,IPC_RMID);
        if(ret == -1)
        {
            fprintf(stderr,"semaphore删除失败:%s!\n",strerror(errno));
            exit(1) ;
        } 

        printf("child exiting successfully!\n");
        exit(0) ;
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值