68-Linux_信号量

信号量

信号量就是控制某个进程能够对某个资源进行访问;保证同一时刻只能由一个进程对
某个资源进程访问;

打印机

一.什么是信号量

信号量是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目, 获取资源时,需要对信号量的值进行原子减一,该操作被称为 P 操作。当信号量值为 0时,代表没有资源可用, P 操作会阻塞。释放资源时,需要对信号量的值进行原子加一,该操作被称为 V操作。信号量主要用来同步进程。 信号量的值如果只取 0,1,将其称为二值信号量。如果信号量的值大于 1,则称之为计数信号量。
注意:正数值; 加一减一是一个原子操作;

临界资源:同一时刻,只允许被一个进程或者线程访问的资源;
临界区:访问临界资源的代码段;
不加控制模拟使用打印机:

比如:进程 a 和进程 b 模拟访问打印机,进程 a 输出第一个字符‘ a’表示开始使用打印机,输出第二个字符‘ a’表示结束使用, b 进程操作与 a 进程相同。(由于打印机同一时刻只能被一个进程使用,所以输出结果不应该出现 abab这样交替的结果)

二.信号量的接口

(1)semget
int semget(key_t key,int nsems,int semflg);
创建或者获取一个已经存在的信号量;
key:两个进程使用相同的key值,就可以使用同一个信号量;
2.思路:
nsems:创建几个信号量;
semflg:标志位;如果为创建:IPC_CREAT;
如果为全新创建,也就是不知道是否有人创建过,则IPC_CREATE|IPC_EXCEL,就是如果没
有则创建,如果有则创建失败 ;
(2)semop:
int semop(int semid,struct sembuf *sops,unsigned nsops);
对信号量进行改变,做P操作或者V操作;
semid:信号量的id号,也就是刚才semget的返回值;说明对哪个信号量进行操作;
sops:结构体指针,指向sembuf的结构体指针,sembuf结构体有三个成员变量:sem_num表
示信号量的编号(即指定信号量集中的信号量下标);sem_op表示是p还是v操作;1为v操作
(1),-1为p操作(1);sem_flg为标志位;
(3)semctl:
int semctl(int semid,int semnum,int cmd,...);
对信号量进行控制:初始化/删除信号量
semid:信号量id;
semnum:信号量编号;
cmd:命令:SETVAL:初始化信号量; IPC_RMID:删除信号量;
**注意**:联合体semun,这个联合体需要自己定义;

在这里插入图片描述

三.信号量的使用

1.思路

在这里插入图片描述

2.代码

sem.h

#include<stdio.h>
#include<unistd.h>
#include<sys/sem.h>

union semun
{
    int val;
};

void sem_init();
void sem_p();
void sem_v();
void sem_destroy();

sem.c

#include"sem.h"

#define SEM_NUM 2
static int semid=-1;

void sem_init()//创建信号量,并初始化
{
    semid=semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
    if(semid==-1)
    {
        semid=semget((key_t)1234,SEM_NUM,0600);
        if(semid==-1)
        {
            perror("semget error\n");
        }
    }
    else
    {
        int arr[SEM_NUM]={1,0};
        for(int i=0;i<SEM_NUM;i++)
        {
            //初始化
            union semun a;
            a.val=1;
            if(semctl(semid,i,SETVAL,a)==-1)//全新创建成功,就初始化
            {
                perror("semctl init error");
            } 
        }     
    }
}

void sem_p()//p操作
{
    struct sembuf buf;
    buf.sem_num=0;
    buf.sem_op=-1;//p操作
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("p errro\n");
    }
}

void sem_v()
{
    struct sembuf buf;
    buf.sem_num=0;
    buf.sem_op=1;//v操作
    buf.sem_flg=SEM_UNDO;
    if(semop(semid,&buf,1)==-1)
    {
        perror("v error\n");
    }
}

void sem_destroy()
{
    if(semctl(semid,0,IPC_RMID)==-1)
    {
        perror(" destroy sem error\n");
    }
}

a.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include"sem.h"

int main()
{
    int i=0;
    sem_init();
    for(;i<5;i++)
    {
        sem_p();
        printf("A");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("A");
        fflush(stdout);
        sem_v();
        n=rand()%3;
        sleep(n);
    }
    sleep(5);
    sem_destroy();
}

b.c

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include"sem.h"

int main()
{
    int i=0;
    sem_init();
    for(;i<5;i++)
    {
        sem_p();
        printf("B");
        fflush(stdout);
        int n=rand()%3;
        sleep(n);
        printf("B");
        fflush(stdout);
        sem_v();
        n=rand()%3;
        sleep(n);
    }
}
3.编译及结果

在这里插入图片描述

四.ipcs命令

ipcs -s:只查看信号量;

ipcs -m:只查看共享内存;

ipcs -q:只查看消息队列;

删除信号量: ipcrm -s 编号;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 中,可以使用 `semctl` 系统调用中的 `GETVAL` 命令来获取指定信号量的值。如果该值为0,则表示信号量已经被占用,没有可用的资源。 具体的代码实现可以参考如下示例: ```c #include <stdio.h> #include <stdlib.h> #include <sys/sem.h> int main() { int semid; struct sembuf sb; // 创建信号量集 semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT); if (semid == -1) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量 if (semctl(semid, 0, SETVAL, 1) == -1) { perror("semctl"); exit(EXIT_FAILURE); } // 获取信号量的值 printf("Sem value: %d\n", semctl(semid, 0, GETVAL)); // 尝试获取信号量 sb.sem_num = 0; sb.sem_op = -1; // P 操作 sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(EXIT_FAILURE); } printf("Semaphore acquired\n"); // 释放信号量 sb.sem_op = 1; // V 操作 if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(EXIT_FAILURE); } printf("Semaphore released\n"); // 删除信号量集 if (semctl(semid, 0, IPC_RMID, 0) == -1) { perror("semctl"); exit(EXIT_FAILURE); } return 0; } ``` 在这个示例中,我们首先使用 `semget` 系统调用创建了一个信号量集,并使用 `semctl` 系统调用对该信号量进行了初始化。然后使用 `semctl` 系统调用获取了该信号量的值,并输出到控制台。 接下来,我们使用 `semop` 系统调用进行了一次 P 操作,即尝试获取该信号量。如果该信号量的值为0,则该操作将会被阻塞,直到信号量的值变为非0。在本例中,由于我们已经将信号量初始化为1,因此该 P 操作可以顺利完成。 最后,我们使用 `semop` 系统调用进行了一次 V 操作,即释放该信号量。然后使用 `semctl` 系统调用删除了该信号量集。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值